Servy has it. You can't require that the type have an indexer, but you can require that the type implements an interface that exposes an indexer. IList
and IDictionary
, and their generic counterparts, are the primary built-in interfaces that expose indexers, with integer and string index values respectively. Unfortunately, a few built-in types, like HttpSessionState, expose indexers of their own accord without implementing an interface identifying that they do so.
You can also define your own indexed interface to apply to any type you control:
public interface IIndexable<TKey, TVal>
{
TVal this[TKey key]{get;}
}
So, best-case, you could implement three overloads of these methods:
public static TElem GetOrNew<TList, TElem>(this TList collection, int key)
where TList : IList<TElem>, TElem:new()
{
...
}
public static TElem Set<TList, TElem>(this TList collection, int key, TElem value)
where TList: IList<TElem>
{
...
}
public static TVal GetOrNew<TDict, TKey, TVal>(this TDict collection, TKey key)
where TDict : IDictionary<TKey, TVal>, TVal : new()
{
...
}
public static TVal Set<TDict, TKey, TVal>(this TDict collection, TKey key, TVal value)
where TDict : IDictionary<TKey, TVal>
{
...
}
public static TVal GetOrNew<TColl, TKey, TVal>(this TDict collection, TKey key)
where TColl : IIndexable<TKey, TVal>, TVal: new()
{
...
}
public static TVal Set<TColl, TKey, TVal>(this TDict collection, TKey key, TVal value)
where TColl : IIndexable<TKey, TVal>
{
...
}
... which would allow you to use this method set on the 90th percentile of objects with an indexer (including Array, which for practical purposes implements IList).