如下所示,用户可以更改只读产品字段/属性:
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#中创建只读对象属性或字段??
谢谢,
答案 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
您有两个选择:
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