Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xslt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
是C#只读字段';是否允许在类外修改?_C# - Fatal编程技术网

是C#只读字段';是否允许在类外修改?

是C#只读字段';是否允许在类外修改?,c#,C#,我有一个通过构造函数参数设置的只读对象字段。如果我修改对象,类中的字段也会改变,我想这是一个引用调用。有什么方法可以更好地做到这一点/防止它 private void Form1_Load(object sender, EventArgs e) { Product p = new Product() { Name="New" }; Store s = new Store(p); p.Name = "MODIFY!"; Mes

我有一个通过构造函数参数设置的
只读
对象字段。如果我修改对象,类中的字段也会改变,我想这是一个引用调用。有什么方法可以更好地做到这一点/防止它

private void Form1_Load(object sender, EventArgs e)
{
    Product p = new Product() { Name="New" };
    Store s = new Store(p);
    p.Name = "MODIFY!";
    MessageBox.Show(s.Show());//MODIFY!
}

public class Store
{
    private readonly Product product;

    public Store(Product product)
    {
        this.product = product;
    }

    public string Show()
    {
        return this.product.Name;
    }
}

public class Product
{
    public string Name { get; set; }
}

您在
只读
字段中存储的内容是一个引用。当然,这个参考是只读的,永远不会更改。但是引用对象的内容仍然可以更改

由于
Product
似乎是一个数据保存类,一种方法可能是简单地将内容复制到一个新实例中:

public class Store
{
    private readonly Product product;

    public Store(Product product)
    {
        // Create a new Product instance that only this Store instance
        // knows about
        this.product = new Product { Name = product.Name };
    }
}
现在,只要不导出此实例,
Store.product
的内容就不能从外部更改。

但是请注意,
存储
类中的代码可能仍然能够更改内容。

如果您不想更改
存储
中的
产品
如果您更改原始实例,则必须在将其分配给字段之前制作一份副本:

public Store(Product product)
{
    this.product = new Product() {Name = product.Name};
}
或者,您可以将
产品
制作为一个结构。结构在传递给方法时始终被复制,而不是通过引用传递:

public struct Product
{
    public string Name { get; set; }
}

另一个选项是创建产品的不可变版本:

public class Product
{
    public string Name { get; set; }

    public Immutable ToImmutable() => new Immutable(this);

    public class Immutable
    {
         public Immutable(Product product) { Name = product.Name; }
         public string Name { get; }
    }
}
现在

public class Store
{
    private readonly Product.Immutable product;

    public Store(Product product)
    {
        this.product = product.ToImmutable();
    }

    public string Show()
    {
        return this.product.Name;
    }
}

福利?任何人都不能在
Store

内部乱搞
product
将变量声明为
const
@SouvikGhosh引用类型字段不能标记为
const
,除非分配了空引用,否则会破坏此处的点。无论采用何种解决方案,除了const之外的任何内容都可以通过反射进行更改。其他一切都只是编译器规则。
readonly
是浅层不变性(只适用于它所应用的变量)。我认为您正在寻找的是深度不变性(递归地应用于它所应用的变量和引用类型的任何字段),这目前不是可用的语言功能。虽然OP确实提到了
对象
,但一种可能的替代方法是将其声明为
结构
。这意味着数据会被复制进来,但假设数据结构很简单。@DiskJunky是的,制作
Product
a
struct
是很有可能的。但我认为这将是对OP的代码的一个更大的改变(不知道该
产品
类在其他地方是如何使用的)。@DiskJunky将它变成一个
结构
只是为了便于复制不是一个好主意,它会改变太多。如果OP想要对象的副本而不是对同一对象的引用,那么他需要复制一份。@DaveCousineau我完全同意。我只是把它作为一种选择,如果结构足够简单的话。尚不清楚这是新代码还是现有代码。@DiskJunky我怀疑您混淆了不变性(这是您在本例中想要的)和
struct
struct
并不能解决任何以这种方式直接或间接引用的可变对象都可以修改的问题。。。也就是说,
struct X{SomeMutableClass Y{get;}}
仍然会有同样的问题,只是多了一个点。