У меня есть класс, который ведет список объектов другого класса. Список объектов является общественной собственностью. Я хотел бы препятствовать тому, чтобы пользователи добавили и удалили объекты непосредственно для списка как это:
MyObject.MyListProperty.Add(object);
Вместо этого я хочу, чтобы они использовали метод, который внутренне сделает некоторую обработку и затем добавит объект перечислить.
У меня есть некоторые идеи:
List
и переопределение добавляет и удаляет Там некоторый набор является интерфейсом, который не имеет, Добавляют и Удаляют?
Править:
Я собираюсь пойти с ReadOnlyCollection
. Причина состоит в том, что перенесенный набор может быть обновлен, и изменения будут сразу видимы в объекте только для чтения (см. примеры кода MSDN для ReadOnlyCollection
и AsReadOnly()
). Это признает, что список только для чтения создается только однажды.
Проблема с IEnumerable
тот объект, может быть литая спина к оригиналу List
и затем непосредственно управляемый.
Вы можете использовать ReadOnlyCollection - заверните свою коллекцию в нее и верните ReadOnlyCollection
пользователям вашего класса:
return new ReadOnlyCollection(innerCollection);
Или используя метод AsReadOnly
класса List
:
return innerCollection.AsReadOnly();
Интерфейс IEnumerable сделает то, что вам нужно, так как он имеет только один член GetEnumerator()
, что позволит вам выполнять итерации только по элементам.
Может быть Метод AsReadOnly сделает трюк, чтобы передать публично экземпляр, доступный только для чтения.
В противном случае, IEnumerable
не имеет ни Add
, ни Remove
, так что вы можете сделать что-то вроде:
private List<int> _myList;
public IEnumerable<int> MyList
{
get
{
return this._myList.ToList();
}
}
Я бы предпочел использовать IEnumerable
(+ копирование), как и для ReadOnlyCollection
, потому что: изменения в вашем базовом списке (из которого создается ваша коллекция, доступная только для чтения) сразу же отобразятся в вашем экземпляре коллекции, доступной только для чтения. это может привести к проблемам с блокировкой и с прямыми линиями :)
Зависит от требуемой информации. Для отладки трассировки стека и внутренних исключений рекомендуется:
string message =
"Exception type " + ex.GetType() + Environment.NewLine +
"Exception message: " + ex.Message + Environment.NewLine +
"Stack trace: " + ex.StackTrace + Environment.NewLine;
if (ex.InnerException != null)
{
message += "---BEGIN InnerException--- " + Environment.NewLine +
"Exception type " + ex.InnerException.GetType() + Environment.NewLine +
"Exception message: " + ex.InnerException.Message + Environment.NewLine +
"Stack trace: " + ex.InnerException.StackTrace + Environment.NewLine +
"---END Inner Exception";
}
-121--630105- См. эту статью о ProductCode и PackageCode: http://www.simple-talk.com/dotnet/visual-studio/updates-to-setup-projects/
В ней объясняется, как ProductCode и PackageCode взаимодействуют во время установки и как настроить проект установки для правильного применения .msi в качестве обновления.
-121--4501564- Нет в поле, только IEnumerable < T >
предоставит его, не открывая Add
и Remove
public methods, которые могут заставить клиента получить исключение во время выполнения.
Если вы хотите, чтобы ваш открытый API явно указал, что коллекция доступна только для чтения и вам нужен индексатор, вам придется написать собственную обертку вокруг существующего списка < T >
или T []
.
Требование вызова hasNext ()
перед вызовом next ()
нарушает контракт итератора
. Вы действительно должны переписать его так, чтобы next ()
просто выбросил NoSuxyElireException
, если нет элемента для возврата.
Иногда используется оператор-запятая, но необходимо убедиться, что ни один оператор-запятая, определенный пользователем, не попадает в путь, так как, например, вы полагаетесь на точки последовательности между левой и правой сторонами или хотите убедиться, что ничего не мешает требуемому действию. Здесь void ()
вступает в игру:
for(T i, j; can_continue(i, j); ++i, void(), ++j)
do_code(i, j);
Игнорируйте места, которые я ставлю для условия и кода. Что важно, так это void ()
, который заставляет компилятор использовать оператор builtin. Иногда это может быть полезно и при реализации классов признаков.
Можно ли просто дать им объект, который всегда возвращает перечислитель, который они могут использовать для доступа к структуре?
Iconlication (нереборежественная версия) только INumerable + Count
Самый простой вариант - открыть список как один из следующих IEnumerable , ICollection ReadOnlyCollection через общедоступное свойство.
Таким образом, вы можете создать свой собственный тип
списка, который предоставляет ваши Items
как один из указанных выше, но имеет внутренний метод для добавления, например
public class MyList<MyType>
{
private List<MyType> items;
public MyList()
{
items = new List<MyType>();
}
public IEnumerable Items { get { return items.AsEnumerable(); } }
public Add(MyType item)
{
// do internal processing
items.Add(item);
}
}
На самом деле не отвечает на ваш вопрос, но является полезной информацией, если вы решите реализовать одну из двух ваших идей: Вы можете использовать ToArray для создания копии и возврата массива.
Или вы можете сделать что-то вроде этого: http://en.csharp-online.net/CSharp_Generics_Recipes%E2%80%94Making_Read-Only_Collections_the_Generic_Way