Как создать свойство объекта только для чтения в C #? - PullRequest
4 голосов
/ 06 октября 2011

Как видно ниже, пользователь может изменить поле / свойство продукта только для чтения:

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 ]

6 голосов
/ 06 октября 2011

Ключевое слово readonly не позволяет вводить новый экземпляр в поле.

Он волшебным образом не делает объект внутри поля неизменным.
Что вы ожидаете, если вы напишите

readonly Product x = Product.Create();

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

Если вы хотите неизменный объект, вам нужно сделать сам класс неизменяемым, удалив все общедоступные сеттеры.

5 голосов
/ 06 октября 2011

Вам необходимо сделать свойство-свойство Name частного набора:

public class Product
{
    private Product(){}

    public string Name { get; private set; }

    public static Product Create(string name)
    {
        return new Product { Name = name };
    }
}
1 голос
/ 06 октября 2011

Проблема, которую вы видите, состоит в том, что вы путаете модификатор 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 - нет. С этой целью, если вы хотите создать свойство только для чтения, вы, вероятно, захотите создать свой тип как неизменяемый, поскольку его внутренняя структура / значения не могут измениться.

0 голосов
/ 06 октября 2011

Чтобы лучше продемонстрировать свойства 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

У вас есть 2 варианта:

  • , если вы не хотите, чтобы какие-либо свойства Product были модифицируемыми (например, неизменяемыми), просто неопределить сеттеры (или сделать сеттеры приватными) и иметь конструктор (или метод фабрики) Product, инициализировать их
  • , если вы все еще хотите, чтобы свойства Product были модифицируемыми, но не когда он является членом Order, тогда создайте интерфейс IProduct со свойствомИмя, определенное как: public string Name { get; }, заставьте Product реализовать этот интерфейс, а затем задайте поле Product типа Order, определенное как: 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
0 голосов
/ 06 октября 2011

ключевое слово readonly означает, что поле может быть установлено только в конструкторе, а значение не может быть изменено.

Если значение является ссылочным типом, оно не делает объект доступным только для чтения

Если вы хотите сделать свойство доступным только для чтения, просто опустите установщик.

0 голосов
/ 06 октября 2011

Поля только для чтения могут всегда быть изменены в конструкторе (как вы делаете). Если вы попытаетесь отредактировать поле в другом месте, вы должны получить ошибку компилятора.

...