Содержит ли C # / CLR механизм для пометки возвращаемых значений свойств только для чтения / неизменяемости? - PullRequest
1 голос
/ 21 июля 2009

Я искал вокруг, и до сих пор не удалось найти хороший способ сделать это. Я уверен, что это общая проблема.

Предположим, у меня есть следующее:

class SomeClass : IComparable
{ 
    private int myVal; 
    public int MyVal
    { 
        get { return myVal; } 
        set { myVal = value; }
    }

    public int CompareTo(object other) { /* implementation here */ }
}

class SortedCollection<T>
{
    private T[] data;
    public T Top { get { return data[0]; } }

    /* rest of implementation here */
}

Идея состоит в том, что я собираюсь реализовать двоичную кучу, и вместо того, чтобы поддерживать только операции Insert () и DeleteMin (), я хочу поддерживать "просмотр" на самом высоком (или наименьшем, в зависимости от обстоятельств) ) значение приоритета в стеке. Никогда не любил Гейзенберга, и весь этот принцип неопределенности «нельзя смотреть на вещи, не меняя их». Мусор!

Проблема, очевидно, заключается в том, что вышеприведенное не предоставляет средств для предотвращения изменения вызывающим кодом MyVal (при условии SortedCollection) через свойство Top, и эта операция имеет явную возможность поместить мою кучу в неправильный порядок. Есть ли способ предотвратить применение модификаций к внутренним элементам кучи через свойство Top? Или я просто использую код с предупреждением: «Стабильно, только если вы не изменяете какие-либо экземпляры между временем их вставки и dequeue'd. YMMV.»

Ответы [ 5 ]

1 голос
/ 21 июля 2009

Чтобы ответить на ваш вопрос: Нет , нет способа реализовать желаемое вами поведение - если T имеет ссылочный тип (и, возможно, даже с некоторыми типами значений)

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

class SomeClass : IComparable
{ 
    private int myVal; 
    public int MyVal
    { 
        get { return myVal; } 
        set { myVal = value; }
    }

    public int CompareTo(object other) { /* implementation here */ }
}


class SortedCollection<T>
{
    private T[] data;
    public T Top { get { return data[0]; } }

    /* rest of implementation here */
}

//..
// calling code
SortedCollection<SomeClass> col;
col.Top.MyVal = 500;  // you can't really prevent this

ПРИМЕЧАНИЕ Я имею в виду, что вы не можете предотвратить это в случае классов, которые вы не контролируете . В примере, как и другие заявили, вы можете сделать набор MyVal закрытым или опустить его; но поскольку SortedColleciton является универсальным классом, вы ничего не можете сделать со структурами других людей ..

1 голос
/ 21 июля 2009

Ваши свойства не обязательно должны иметь одинаковую доступность для get / set. Это распространяется на все, что возвращает тип значения (обычно struct s, который содержит только типы значений) или неизменяемые ссылочные типы .

public int MyVal
{ 
    get { return myVal; } 
    private set { myVal = value; }
}

Для изменяемых ссылочных типов у вас есть другие опции, такие как возврат Clone() s или использование ReadOnlyCollection<T>, чтобы не дать вызывающей стороне их изменить:

private List<int> data;

public IList<int> Data
{
    get { return new ReadOnlyCollection<int>(this.data); }
}
1 голос
/ 21 июля 2009

Вы можете иметь свойство только для чтения (то есть свойство только с геттером):

private int myVal;
public int MyVal { get { return myVal; } }

Но будьте осторожны: это может не всегда работать так, как вы ожидаете. Рассмотрим:

private List<int> myVals;
public List<int> MyVals { get { return myVals; } }

В этом случае вы не можете изменить, какой List использует класс, но вы все равно можете вызывать методы этого списка .Add(), .Remove() и т. Д.

0 голосов
/ 21 июля 2009

Теперь я понимаю вашу проблему. Я думаю, что это должно работать:

class SortedCollection<T> where T: ICloneable
{
    private T[] data;
    public T Top 
    { 
         get 
         { 
             T ret = (T)data[0].Clone();
             return ret; 
         }
    }

    /* rest of implementation here */
}

Ограничение ICloneable гарантирует, что параметр типа реализует интерфейс ICloneable. (если это приемлемо)

0 голосов
/ 21 июля 2009

Реализуйте методы получения только для ваших свойств и изменяйте коллекцию, используя методы добавления / удаления

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...