Ограничение доступа к вызовам методов для свойств только для чтения - PullRequest
3 голосов
/ 14 января 2009

У меня есть класс, который определяет свойство только для чтения, которое эффективно предоставляет приватное поле, что-то вроде этого:

public class Container
{
    private List<int> _myList;

    public List<int> MyList
    {
        get { return _myList;}
    }

    public Container() : base ()
    {
        _myList = new List<int>();
    }

    // some method that need to access _myList
    public SomeMethod(int x)
    {
         _myList.Add(x);
    }
}

теперь потребитель не может напрямую управлять моей собственностью, поэтому используйте код aContainer.MyList = new List (); генерирует ошибку во время компиляции. Однако потребитель может абсолютно свободно вызывать все виды методов по полученной ссылке, так что это совершенно правильный код

Container c = new Container();  
Console.WriteLine(c.MyList.Count);  
c.MyList.Add(4);  
Console.WriteLine(c.MyList.Count);  

, который побеждает всю концепцию только для чтения.

Есть ли какой-нибудь разумный обходной путь, который позволил бы мне иметь реальную ссылку только для чтения?

P.S. Я не могу просто вернуть копию списка, потому что тогда пользователь будет думать, что он внес все необходимые изменения, но, увы ... они пропадут.

Ответы [ 5 ]

5 голосов
/ 14 января 2009

Не возвращайте прямую ссылку на ваш список. Вместо этого верните ReadOnlyCollection, обернутый вокруг него, или, если возвращаемый тип List <> установлен в камне, верните копию вашего списка. Они могут делать с копией все, что захотят, не затрагивая оригинал.

2 голосов
/ 14 января 2009

Вы можете вернуть Коллекция только для чтения , например:

    public ReadOnlyCollection<int> MyList
    {
        get { return _myList.AsReadOnly(); }
    }

или верните новый список, чтобы вызывающий абонент мог изменить список без изменения исходного списка.

    public List<int> MyList
    {
        get { return new List<int>(_myList)}
    }
2 голосов
/ 14 января 2009

Ссылка "только для чтения" , фактический объект. То есть Вы не можете заменить ссылку другим объектом. Так что если у вас есть класс, который ломает его так:

public class Container
{
    private readonly  List<int> _myList;

    public List<int> MyList
    {
        get { return _myList;}
    }

    public Container() : base ()
    {
        _myList = new List<int>();
    }

    public void BreakReadOnly()
    {
        _myList = new List<int>();
    }
}

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

Если вам действительно нужна коллекция только для чтения, вы можете сделать это следующим образом:

    public ReadOnlyCollection<int> MyList
    {
        get { return _myList.AsReadOnly(); }
    }

Надеюсь, это поможет.

Обновлено : Удалено использование IEnumerable.

1 голос
/ 14 января 2009

Взгляните на статический метод Array.AsReadOnly () , который вы можете использовать для возврата обертки вокруг массива, которая предотвращает его изменение.

0 голосов
/ 14 января 2009

Вы хотите _myList, который является ссылочным типом, который будет доступен только для чтения. Ну, это только для чтения и нет никакого поражения концепции только для чтения.

CLR реализует свойство readonly для ссылочных типов таким образом, что ссылка (указатель на объект, если вы хотите) - это то, что делается только для чтения, в то время как объект, на который указывает ссылка, может быть изменен.

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

Вы можете реализовать свой неизменяемый универсальный класс коллекции, который будет вести себя так же, как объект List <>, но иметь члены только для чтения.

...