'Why it is not possible to define generic indexers in .NET?

Why can't you create a generic indexer in .NET?

the following code throws a compiler error:

public T this<T>[string key]
{
    get => /* Return generic type T. */
}

Does this mean you can't create a generic indexer for a generic member collection?



Solution 1:[1]

Here's a place where this would be useful. Say you have a strongly-typed OptionKey<T> for declaring options.

public static class DefaultOptions
{
    public static OptionKey<bool> SomeBooleanOption { get; }
    public static OptionKey<int> SomeIntegerOption { get; }
}

Where options are exposed through the IOptions interface:

public interface IOptions
{
    /* since options have a default value that can be returned if nothing's
     * been set for the key, it'd be nice to use the property instead of the
     * pair of methods.
     */
    T this<T>[OptionKey<T> key]
    {
        get;
        set;
    }

    T GetOptionValue<T>(OptionKey<T> key);
    void SetOptionValue<T>(OptionKey<T> key, T value);
}

Code could then use the generic indexer as a nice strongly-typed options store:

void Foo()
{
    IOptions o = ...;
    o[DefaultOptions.SomeBooleanOption] = true;
    int integerValue = o[DefaultOptions.SomeIntegerOption];
}

Solution 2:[2]

I don't know why, but indexers are just syntactic sugar. Write a generic method instead and you'll get the same functionality. For example:

   public T GetItem<T>(string key)
   {
      /* Return generic type T. */
   }

Solution 3:[3]

Properties can't be generic in C#2.0/3.0 so therefore you can't have a generic indexer.

Solution 4:[4]

You can; just drop the <T> part from your declaration and it will work fine. i.e.

public T this[string key]
{
   get { /* Return generic type T. */ }
}

(Assuming your class is generic with a type parameter named T).

Solution 5:[5]

I like the ability to have an indexer without handing out a direct reference to the "indexed" item. I wrote a simple "call back" Indexer class below ...

R = the returned type from the indexer P = the passed type into the indexer

All the indexer really does is pass the operations to the deployer and allow them to manage what actually occurs and gets returned.

public class GeneralIndexer<R,P>
    {
        // Delegates
        public delegate R gen_get(P parm);
        public delegate void gen_set(P parm, R value);
        public delegate P[] key_get();

        // Events
        public event gen_get GetEvent;
        public event gen_set SetEvent;
        public event key_get KeyRequest;

        public R this[P parm]
        {
            get { return GetEvent.Invoke(parm); }
            set { SetEvent.Invoke(parm, value); }
        }

        public P[] Keys
        {
            get
            {
                return KeyRequest.Invoke();
            }
        }

    }

To use it in a program or class:

private GeneralIndexer<TimeSpan, string> TimeIndex = new GeneralIndexer<TimeSpan,string>();

{
            TimeIndex.GetEvent += new GeneralIndexer<TimeSpan, string>.gen_get(TimeIndex_GetEvent);
            TimeIndex.SetEvent += new GeneralIndexer<TimeSpan, string>.gen_set(TimeIndex_SetEvent);
            TimeIndex.KeyRequest += new GeneralIndexer<TimeSpan, string>.key_get(TimeIndex_KeyRequest);

}

works like a champ especially if you want to monitor access to your list or do any special operations when something is accessed.

Solution 6:[6]

In recent C-sharp you can declare the return type as "dynamic". This is the same as using "object" except that the C# runtime will allow you to use it in code as if it was the type you think it is and then check at run-time to be sure you were right...

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3
Solution 4 Greg Beech
Solution 5 Stuart Peacock
Solution 6 Jeffrey Kesselman