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

发布于 2024-12-08 15:15:21 字数 929 浏览 0 评论 0原文

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

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# 中创建只读对象属性或字段?!

谢谢,

As can be seen below, the user is able to change the readonly product field/property:

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 };
        }
    }

I thought it's quite basic but it doesn't seem so.

How to Create a Read-Only Object Property or Field in C#?!

Thanks,

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

平安喜乐 2024-12-15 15:15:21

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

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

readonly Product x = Product.Create();

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

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

The readonly keyword prevents you from putting a new instance into the field.

It doesn't magically make any object inside the field immutable.
What do you expect to happen if you write

readonly Product x = Product.Create();

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

If you want an immutable object, you need to make the class itself immutable by removing all public setters.

谁许谁一生繁华 2024-12-15 15:15:21

您需要将 Product 的 Name-property 设置为私有:

public class Product
{
    private Product(){}

    public string Name { get; private set; }

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

You need to make the Name-property of Product private set:

public class Product
{
    private Product(){}

    public string Name { get; private set; }

    public static Product Create(string name)
    {
        return new Product { Name = name };
    }
}
小情绪 2024-12-15 15:15:21

您看到的问题是您将 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 的内部结构却不是。为此,如果您想创建只读属性,您可能希望将类型创建为不可变的 - 因为其内部结构/值无法更改。

The problem you are seeing is that you're confusing the readonly modifier with what you think is a read-only property. The readonly modifier ensures that the field can only be assigned to through initialisation or a constructor, e.g here are valid uses of 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.
}

What you are finding, is that your Person class itself is mutable, this means although the field Order.Product is readonly, the internal structure of Person is not. To this end, if you want to make a readonly property, you'll likely want to create your type as immutable - being that its internal structure/values cannot change.

小…楫夜泊 2024-12-15 15:15:21

只读字段总是可以在构造函数中修改(正如您所做的那样)。如果您尝试在其他地方编辑该字段,您应该会收到编译器错误。

Readonly fields can always be modified in the constructor (as you're doing). If you try to edit the field elsewhere, you should get a compiler error.

阳光①夏 2024-12-15 15:15:21

readonly 关键字意味着该字段只能在构造函数中设置该值无法更改。

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

如果要将属性设为只读,只需省略 setter 即可。

the readonly keyword means the field can only be set in the constructor & the value cannot be changed.

If the value is a reference type, it doesn't make the object read-only

If you want to make the property readonly, just omit the setter.

烟燃烟灭 2024-12-15 15:15:21

为了更好地演示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

将属性Name的setter设置为私有后(例如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(或使 setters 私有)并让 Product 的构造函数(或工厂方法)初始化它们
  • 如果您仍然希望产品的属性可以修改但当它是 Order 的成员时则不然,然后创建一个接口 IProduct,其属性 Name 定义为: public string Name { get; },使 Product 实现此接口,然后将 Order 类型的 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

To better demonstrate the properties of 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

After making setter of property Name private (e.g. public string Name { get; private set; }):

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

The problem with this solution, of course is:

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

You have 2 options:

  • if you don't want any properties of Product be modifiable (e.g. be immutable) then simply don't define setters (or make setters private) and have constructor (or factory method) of Product initialize them
  • if you still want properties of Product be modifiable but not when it's a member of Order then create an interface IProduct with property Name defined as: public string Name { get; }, make Product implement this interface, and then make Product field of type Order defined as: public readonly IProduct Product;

Any of this solutions will achieve both of your requirements:

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

With only difference between them:

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文