c # только для чтения объекта - PullRequest
22 голосов
/ 23 августа 2010

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

public class Person
{
    public String FirstName { get; set; }
    public String LastName { get; set; }
}

public class SomeClass
{
    public SomeClass(Person manager)
    {
        if (manager == null)
            throw new ArgumentNullException("manager");

        _manager = manager;
    }

    private readonly Person _manager;
    public Person Manager
    {
        get { return _manager; } //How do I make it readonly period!
    }
}

Это единственный способ сделать это, возвращая Clone (), чтобы любые изменения были внесены в клон, а не воригинал?Я знаю, что для массивов есть функция, которая возвращает массив только для чтения.О, и я знаю, что это ссылочный тип ... Кроме того, мне интересно, есть ли какая-то скрытая функция C # для блокировки записывающей части.

Я пытался придумать класс-обертку для чтения ReadOnly, ноЯ не могу понять, как получить свойства для чтения только без дорогостоящего отражения и тому подобного.

О, и я действительно стараюсь не создавать вторую версию класса, которая имеет свойства только для чтения.В этот момент я мог бы также вернуть клона.

Ответы [ 8 ]

38 голосов
/ 23 августа 2010

Чтобы уберечь себя от создания дополнительного класса, вы можете заставить его реализовать его в качестве интерфейса IPerson, который имеет только свойства только для чтения.

public interface IPerson
{
    string FirstName { get; }
    string LastName { get; }
}
public class Person:IPerson
{
    public String FirstName { get; set; }
    public String LastName { get; set; }
}

public class SomeClass
{
public SomeClass(Person manager)
{
    if (manager == null)
        throw new ArgumentNullException("manager");

    _manager = manager;
}

private readonly Person _manager;
public IPerson Manager
{
    get { return _manager; } //How do I make it readonly period!
}
}
6 голосов
/ 23 августа 2010

Вы можете преобразовать класс Person в неизменный объект, как показано ниже ..

public class Person 
{ 
    public Person( string firstName, string lastName )
    {
        FirstName = firstName;
        LastName = lastName;
    }

    public String FirstName { get; private set; } 
    public String LastName { get; private set; } 

} 
4 голосов
/ 23 августа 2010

Вы можете заморозить объект (сделать его неизменным) при некоторых условиях с помощью Castle.DynamicProxy.Прочитайте этот блог сообщение для деталей.

2 голосов
/ 27 февраля 2012

Вот другой пример, основанный на том, как List.AsReadOnly реализован в .NET Framework 2.0.Логическое (IsReadOnly) используется в соответствующих методах для предотвращения обновлений:

public class Person
{
    private string _firstName;
    public string FirstName
    {
        get { return _firstName; }
        set
        {
            if (!IsReadOnly) _firstName = value;
            else throw new AccessViolationException("Object is read-only.");
        }
    }

    private string _lastName;
    public string LastName
    {
        get { return _lastName; }
        set
        {
            if (!IsReadOnly) _lastName = value;
            else throw new AccessViolationException("Object is read-only.");
        }
    }

    internal virtual bool IsReadOnly { get { return false; } }

    public ReadOnlyPerson AsReadOnly()
    {
        return new ReadOnlyPerson(this);
    }

    public class ReadOnlyPerson : Person
    {
        private Person _person;
        internal override bool IsReadOnly { get { return true; } }

        internal ReadOnlyPerson(Person person) // Contructor
        {
            this._person = person;
        }
    }
}

Для проверки:

static void Main(string[] args)
{
    Person p1 = new Person();
    p1.FirstName = "Joe";
    p1.LastName = "Bloe";
    Console.WriteLine("First = {0} Last = {1}", p.FirstName, p.LastName);

    var p2 = p1.AsReadOnly();
    p2.FirstName = "Josephine"; // AccessViolationException
}
2 голосов
/ 23 августа 2010

Такой функции нет - вы указали свои варианты.

Либо клонируйте ее, либо сделайте доступным только для чтения тип Person.Последний подход обычно предпочтительнее, потому что семантика более ясна: для вызывающих абонентов очевидно, что они не должны (и не могут) изменять экземпляр.

1 голос
/ 23 августа 2010

Не существует способа сделать все свойства вашего объекта доступными только для чтения из класса.В приведенном выше примере вы не можете сделать свойства _manager доступными только для чтения, если только вы не изменили свойства в классе Person, чтобы они были доступны только для чтения.

Вы можете сделать установщик свойств класса Person внутренним, что означает, что только классы внутрита же сборка, что и Person, может изменять свойства.

Или, если вы сделаете установщик свойств закрытым, тогда только код в Person может изменять значения свойств.

0 голосов
/ 24 августа 2010

Анонимные объекты доступны только для чтения.

0 голосов
/ 23 августа 2010

Нет. Вы ищете что-то вроде C ++ - стиля const -ness, и по различным причинам C # этого не имеет.

Однако анонимные типы действительно неизменны.

...