如何在C#中创建只读对象属性?

时间:2011-10-06 13:48:10

标签: c# asp.net properties readonly

如下所示,用户可以更改只读产品字段/属性:

class Program
    {
        static void Main(string[] args)
        {
            var product = Product.Create("Orange");
            var order = Order.Create(product);
            order.Product.Name = "Banana"; // Main method shouldn't be able to change any property of product!
        }
    }

    public class Order
    {
        public Order(Product product)
        {
            this.Product = product;
        }

        public readonly Product Product;

        public static Order Create(Product product)
        {
            return new Order (product);
        }
    }

    public class Product
    {
        private Product(){}

        public string Name { get; set; }

        public static Product Create(string name)
        {
            return new Product { Name = name };
        }
    }

我认为这很基本,但似乎并非如此。

如何在C#中创建只读对象属性或字段??

谢谢,

6 个答案:

答案 0 :(得分:6)

readonly关键字阻止您将新实例放入字段中。

它不会神奇地使字段内的任何对象不可变 如果你写

,你会发生什么?
readonly Product x = Product.Create();

Product y;
y = x;
y.Name = "Changed!";

如果你想要一个不可变对象,你需要通过删除所有公共setter来使类本身不可变。

答案 1 :(得分:5)

您需要将Product的属性设置为私有集:

public class Product
{
    private Product(){}

    public string Name { get; private set; }

    public static Product Create(string name)
    {
        return new Product { Name = name };
    }
}

答案 2 :(得分:1)

您遇到的问题是,您将readonly修饰符与您认为的只读属性混淆。 readonly修饰符确保只能通过初始化或构造函数来分配字段,例如,此处是readonly的有效用途:

public class MyClass
{
  private readonly int age = 27; // Valid, initialisation.
}

public class MyClass
{
  private readonly int age;

  public MyClass() 
  {
    age = 27; // Valid, construction.
  }
}

public class MyClass
{
  private readonly int age;

  public int Age { get { return age; } set { age = value; } } // Invalid, it's a readonly field.
}

您所发现的是,您的Person类本身是可变的,这意味着虽然字段Order.Product是只读的,但Person的内部结构却不是。为此,如果要创建只读属性,您可能希望将类型创建为不可变 - 因为其内部结构/值不能更改。

答案 3 :(得分:0)

Readonly字段可以在构造函数中始终进行修改(正如您所做的那样)。如果您尝试在其他地方编辑该字段,则应该收到编译器错误。

答案 4 :(得分:0)

readonly关键字表示该字段只能在构造函数&中设置。价值无法改变。

如果值是引用类型,则不会使对象成为只读

如果您想要只读属性,只需省略setter。

答案 5 :(得分:0)

为了更好地展示readonly

的属性
order.Product = Product.Create("Apple") // <- not allowed because Product field is readonly
order.Product.Name = "Apple" // <- allowed because Name is not readonly field or private property

将属性名称设为私有(例如public string Name { get; private set; })后:

order.Product.Name = "Apple" // <- not allowed

此解决方案的问题当然是:

new Product { Name = "Orange" } // <- not allowed if called from outside Product class

您有两个选择:

  • 如果您不希望Product的任何属性可修改(例如,是不可变的),那么只是不定义setter(或使setter私有)并且让Product的构造函数(或工厂方法)初始化它们
  • 如果您仍然希望Product的属性可以修改,但是当它是Order的成员时,则创建一个接口IProduct,其属性Name定义为:public string Name { get; },make Product实现此接口,然后生成类型的Product字段订单定义为:public readonly IProduct Product;

任何此解决方案都将满足您的两个要求:

order.Product.Name = "Apple" // <- not allowed
new Product { Name = "Orange" } // <- allowed when called from Product's Create method

只有它们之间的区别:

order.Product.Name = "Apple" // <- not allowed
Product product = new Product { Name = "Orange" } // not allowed in solution #1 when called from outside Product, allowed in solution #2
product.Name = "Apple" // <- not allowed in solution #1 but allowed in solution #2