为什么 “in” 关键字允许在 C# 中更改属性?

huangapple go评论67阅读模式
英文:

Why does the "in" keyword allow mutation of properties C#?

问题

我目前正在处理一个函数,其中传递了一个对象(自己编写的类型 Catalog),并且在调用的函数中不应该被改变。这里是一个快速示例。

public override bool Migrate(in Catalog fromCatalog)
{
    fromCatalog.SupplierId = 1; //可以工作,但为什么
}

我想严格地阻止这种行为,并禁止修改传递对象的任何属性

英文:

I am currently working on a function where an object (of self written type Catalog) is passed and shall not be mutated / changed in the called function. Here a quick example.


public override bool Migrate(in Catalog fromCatalog)
{
    fromCatalog.SupplierId = 1; //works, but why
}

I want to strictly undermine this behaviour and disallow mutating any properties of the passed object.

答案1

得分: 2

因为 in 修饰符仅适用于变量(在此情况下是参数)。它防止参数的值被更改以指向不同的对象。

public bool Migrate(in Catalog fromCatalog)
{
/* 错误 CS8331  无法将值分配给变量 'fromCatalog' 
或将其用作 ref 分配的右侧,因为它是一个只读变量 */
    fromCatalog = new Catalog(); 

    fromCatalog.SupplierId = 1;
}

并创建对象的浅拷贝,以确保您不会更改传递的对象(在类内部)。

示例

public Catalog CreateACopy()
{
    Catalog obj = (Catalog)this.MemberwiseClone();
    // 和其他...
    return obj;
}
        

用法

public class Program 
{
    private static void Main()
    {
        Catalog catalog = new Catalog();
        new Program().Migrate(catalog.CreateACopy());
    }
    public bool Migrate(in Catalog fromCatalog)
    {
        fromCatalog.SupplierId = 1;
    }
}
英文:

Because the in modifier applies only to the variable (the parameter in this case). It prevents the parameter from having its value changed to refer to a different object.

public bool Migrate(in Catalog fromCatalog)
{
/* Error CS8331  Cannot assign to variable 'fromCatalog' 
or use it as the right hand side of a ref assignment 
because it is a readonly variable */
    fromCatalog = new Catalog(); 

    fromCatalog.SupplierId = 1;
}

and create a shallow copy of the object so that you don't change anything in the object you passed (within the class)

example:

public Catalog CreateACopy()
{
    Catalog obj = (Catalog)this.MemberwiseClone();
    // and other...
    return obj;
}

utilization:

public class Program 
{
    private static void Main()
    {
        Catalog catalog = new Catalog();
        new Program().Migrate(catalog.CreateACopy());
    }
    public bool Migrate(in Catalog fromCatalog)
    {
        fromCatalog.SupplierId = 1;
    }
}

答案2

得分: 1

它有效是因为 Catalog 具有可写属性。C#没有与C ++等常量值概念相同的概念。因此,fromCatalog 只是另一个可以传递、调用方法、设置属性等的值。

但这并不意味着编写这样的代码有多大意义。in 关键字主要用于避免对值类型进行副本。但如果值类型是可变的,编译器仍然必须创建一个防御性副本,以防止原始对象被修改。

因此,一般建议是使您的值类型不可变/只读,这可以避免这个问题。另请参阅为什么可变结构体是邪恶的

英文:

It works because the Catalog has a writeable property. C# does not have a concept of constant values the same way for example C++ does. So fromCatalog is just another value you can pass around, call methods on, set properties, etc.

But that does not mean it makes much sense to write code like this. The in keyword is mostly useful to avoid copies of a value type. But if the value type is mutable the compiler has to create a defensive copy anyway, just to prevent the original object from being modified.

So the general recommendation is to make your value types immutable/readonly, this avoids the issue. See also why mutable structs are evil.

huangapple
  • 本文由 发表于 2023年7月24日 17:46:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/76753239.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定