简体   繁体   中英

Indexer constraint on generic types

Is it possible to create a generic class/method where the type must have an indexer?

My thought was to make the following two extension methods work on any type which uses an indexer for getting and setting values, but can't seem to find anything about it. Only stuff about making the indexer itself generic, which is not what I'm after...

    public static T GetOrNew<T>(this HttpSessionStateBase session, string key) where T : new()
    {
        var value = (T) session[key];
        return ReferenceEquals(value, null) 
            ? session.Set(key, new T()) 
            : value;
    }

    public static T Set<T>(this HttpSessionStateBase session, string key, T value)
    {
        session[key] = value;
        return value;
    }

There is no way to apply a generic constraint that the generic type argument have an indexer (or any operator). The best that you can do is create an interface with that restriction and restrict the generic argument to implementing that interface.

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).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM