Существуют ли какие-либо коллекции в .NET, которые предотвращают нулевые записи?
Я специально думаю о коллекции, которая соответствует контракту набора, но я думаю, что этот вопрос может быть применим к любому типу. Существуют ли коллекции в .NET Framework, которые предотвращают появление нулевых записей? Мне нужно конкретное поведение:
var set = new HashSet<object>();
bool added = set.Add(null);
Console.WriteLine(added); // prints "False"
Это не поведение встроенного HashSet<T>
. Существуют ли какие-либо коллекции, которые имеют это (или подобное) поведение, или мне лучше сворачивать мои собственные? Если последний, какой лучший способ это сделать? Должен ли я наследовать непосредственно из HashSet<T>
или просто обернуть его?
EDIT: Чтобы быть ясным, это просто праздное удивление. В основном потому, что я не могу думать о какой-либо причине, которую я когда-либо хотел бы разрешить null
в наборе объектов. У меня нет никакой особой необходимости.
Ответы
Ответ 1
Не существует встроенного класса, подобного HashSet<T>
, за исключением этого единственного поведения.
Если вам это нужно, я бы рекомендовал перепродать. Однако я не рекомендую подклассы HashSet<T>
. Ни один из методов (например, Add
, который вы явно хотите изменить) является виртуальным, поскольку он не был специально разработан с учетом подкласса. Это вызовет странное поведение использования, поскольку вы будете скрывать унаследованные методы.
Просто инкапсулируйте a HashSet<T>
и выставляйте членов, которые вам нужны. Единственный реальный "код", который вам нужно добавить, - это одиночная проверка нуля в методе "Добавить" - иначе просто передайте все методы инкапсулированному экземпляру.
Если вы хотите, чтобы это был общий класс, вам нужно добавить дополнительное ограничение для работы только с классами, так как вы хотите иметь нулевую проверку:
public class ValueSet<T> : ICollection<T>, IEnumerable<T>, ICollection
where T : class
{
private HashSet<T> hashSet = new HashSet<T>();
// ... Implement all members as needed...
Ответ 2
Как написать метод расширения для HashSet. Это может быть проще всего сделать.
public static class HashSetExtensions
{
public static bool AddNonNull<T>(this HashSet<T> set, T item)
where T : class
{
if (item == null)
return false;
return set.Add(item);
}
}
Затем вы можете сделать следующее:
HashSet<object> test = new HashSet<object>();
test.AddNonNull(null); //Will return false;
Ответ 3
Как вы отметили этот вопрос с помощью generics
, я предполагаю, что вы ищете общую коллекцию. Такая коллекция не существует в платформе .NET просто потому, что типы значений не могут быть null
, поэтому, я думаю, вам придется сворачивать свой собственный, добавив ограничение ограничения на общий тип, который он принимает.
Ответ 4
Мне не известно о какой-либо сборке .NET, которая делает это, поскольку на основе типа, переданного null, фактически является допустимой записью, поэтому добавление успешно.
Скорее всего, я начну с класса System.Collections.ObjectModel.Collection для того, чтобы вы могли переместить свой собственный.
Ответ 5
A System.Collections.Generics.Dictionary<TKey, TValue>
не позволяет добавлять null
для TKey
(генерирует исключение). Вы должны проигнорировать TValue
, а затем в своем сценарии, если вы намереваетесь использовать его таким образом, и функциональность будет похожа на Hashset<T>
, за исключением операций с фантастическим набором, конечно.
Конечно, немного неуклюжий, но, возможно, это обходное решение для вас в то же время, прежде чем вы сможете придумать свой собственный тип коллекции.
Ответ 6
Даже если вам удастся исключить ДОБАВИТЬ нулевые записи, вы не сможете предотвратить ВХОД пустых записей внутри набора - по крайней мере, не с помощью вашего класса Set
.
Возьмем любой Set<T>
, где T
- тип с нулевым значением. После того, как вы добавили некоторые ненулевые записи, вы можете взять любой из них и установить его в null. Поскольку эта команда не имеет ничего общего с классом Set
, она не может быть обнаружена и не предотвращена классом Set
.
Ответ 7
Два варианта:
Изменить: Извините, я пропустил, ему нужен набор, а не коллекция. По крайней мере, предпочтительный пункт, указанный мной, по-прежнему действителен.:)
Предпочтительно:
В методе, который добавляет элементы в коллекцию, введите ArgumentNullException
, если они вызываются с недопустимым значением.
Не рекомендуется:
Вывести из Collection<T>
и переопределить InsertItem
и SetItem
, чтобы выбросить ArgumentNullException
, если значение равно null.
Ответ 8
В любом случае вы можете использовать Code Contracts в .NET 4.0, чтобы предотвратить добавление значений null
в коллекцию. Таким образом, вы также получите время компиляции, проверяя правильность кода (используя статический анализ, предоставляемый Code Contracts):
public class MyClass {
private List<Something> nonNullList;
[ContractInvariantMethod]
void NonNullEntries() {
Contract.Invariant(Contract.ForAll(nonNullList, el => el != null));
}
public void Add(Something el) {
Contract.Requires(el != null);
}
}
Метод, отмеченный ContractInvariantMethod
, указывает условие, которое должно сохраняться всегда (в списке нет элементов null
). Я считаю, что статический анализ не может объяснить это (из-за ForAll
), но я могу ошибаться. Однако, конечно, можно проверить, вы вызываете метод Add
с правильными (не нулевыми) аргументами.
Ответ 9
Как ответили другие, нет класса Set, который не допускает null. Сказав это, я поделюсь простым решением, которое я использовал в нескольких ситуациях. В моем случае я разрабатывал методы, которые принимали аргументы HashSet, потому что мне нужно было обеспечить, чтобы я получал уникальные объекты. Я не хотел иметь возможный нуль в наборе, и я не хотел проверять значение null каждый раз, когда я перечислял элементы и выполнял над ними операции. Мое решение состояло в том, чтобы просто вызвать remove null в случае, если был null.
public void MyMethod(HashSet<SomeType> set)
{
// remove null item in case it there
set.Remove(null);
foreach (var item in set)
{
// safe to assume item is not null
item.DoSomething();
}
}
Ответ 10
Тебе придется сворачивать. Если вы хотите добавить для возврата bool (независимо от того, был ли элемент ненулевым и, следовательно, добавлен или обратный), вам придется начинать с нуля. Я мог бы рекомендовать унаследовать от List и метать ArgumentNullExceptions. Я имею в виду, что если вы действительно не хотите добавлять нули, исключения могут быть лучшим способом и, безусловно, будет проще.