В этой теме
Как получить null вместо KeyNotFoundException доступ к значению словаря по ключу?
в моем собственном ответе я использовал явную реализацию интерфейса, чтобы изменить базовое поведение индексатора словаря, чтобы не выбрасывать KeyNotFoundException
, если ключ не присутствовал в словаре (поскольку мне было удобно получить null
в таком случае прямо встроенный).
Вот:
public interface INullValueDictionary<T, U>
where U : class
{
U this[T key] { get; }
}
public class NullValueDictionary<T, U> : Dictionary<T, U>, INullValueDictionary<T, U>
where U : class
{
U INullValueDictionary<T, U>.this[T key]
{
get
{
if (ContainsKey(key))
return this[key];
else
return null;
}
}
}
Так как в реальном приложении у меня был список словарей, мне нужен был способ доступа к словарям из коллекции в качестве интерфейса. Я использовал простой индексатор int
для доступа к каждому элементу списка.
var list = new List<NullValueDictionary<string, string>>();
int index = 0;
//...
list[index]["somekey"] = "somevalue";
Проще всего было сделать что-то вроде этого:
var idict = (INullValueDictionary<string, string>)list[index];
string value = idict["somekey"];
Вопрос возник, когда я решил попробовать использовать функцию ковариации, чтобы вместо этого использовать набор интерфейсов. Поэтому мне понадобился интерфейс с параметром ковариантного типа для работы приведения. Первое, что пришло мне в голову, это IEnumerable<T>
, поэтому код будет выглядеть так:
IEnumerable<INullValueDictionary<string, string>> ilist = list;
string value = ilist.ElementAt(index)["somekey"];
Не очень приятно, кроме того, что ElementAt
вместо индексатора намного хуже. Индексатор для List<T>
определен в IList<T>
, а T
не является ковариантным.
Что мне было делать? Решил написать свой:
public interface IIndexedEnumerable<out T>
{
T this[int index] { get; }
}
public class ExtendedList<T> : List<T>, IIndexedEnumerable<T>
{
}
Ну, несколько строчек кода (мне даже не нужно ничего писать в ExtendedList<T>
), и работает так, как я хотел:
var elist = new ExtendedList<NullValueDictionary<string, string>>();
IIndexedEnumerable<INullValueDictionary<string, string>> ielist = elist;
int index = 0;
//...
elist[index]["somekey"] = "somevalue";
string value = ielist[index]["somekey"];
Наконец, вопрос: можно ли каким-то образом добиться этого ковариантного приведения без создания дополнительной коллекции?
TryGetValue(key)
? - person jgauffin   schedule 04.01.2013ielist[index]["somekey"]
а неelist[index]["somekey"]
в последнем разделе? - person Ilya Ivanov   schedule 04.01.2013TryGetValue
мне не удобно. - person horgh   schedule 04.01.2013IList<TSource> tSources = source as IList<TSource>; if (tSources != null) { return tSources[index]; } //... Rest of code
(к тому же я был неправ, это неICollection
, аIList<T>
, который должен быть реализован, что является более строгим - person Marcin Deptuła   schedule 04.01.2013