为什么不能在.NET中定义通用索引器?

时间:2009-01-30 07:49:25

标签: c# .net generics

为什么不能在.NET中创建通用索引器?

以下代码抛出编译器错误:

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

这是否意味着您无法为通用成员集合创建通用索引器?

7 个答案:

答案 0 :(得分:27)

这是一个有用的地方。假设您有一个强类型OptionKey<T>来声明选项。

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

通过IOptions界面公开选项:

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);
}

然后,代码可以使用通用索引器作为一个很好的强类型选项存储:

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

答案 1 :(得分:18)

属性在C#2.0 / 3.0中不能通用,因此您不能拥有通用索引器。

答案 2 :(得分:16)

我不知道为什么,但索引器只是语法糖。写一个通用的方法,你将获得相同的功能。例如:

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

答案 3 :(得分:11)

你可以;只需从您的声明中删除<T>部分,它就可以正常工作。即。

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

(假设您的类是通用的,名为T的类型参数。)

答案 4 :(得分:2)

我喜欢没有分发索引器的能力 直接引用“索引”项。我写了一个简单的 “回拨”下面的索引器类......

R =索引器返回的类型 P =传递给索引器的类型

所有索引器确实是将操作传递给 部署者并允许他们管理实际发生的事情 然后回来了。

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();
            }
        }

    }

在程序或类中使用它:

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

}
如果你想监视访问权限,

就像一个冠军 您的列表或在访问某些内容时执行任何特殊操作。

答案 5 :(得分:1)

我能想到的唯一可以使用的就是这些:

var settings = ConfigurationSection.AppSettings;
var connectionString = settings<string>["connectionString"];
var timeout = settings<int>["timeout"];

但实际上并没有给你买任何东西。您刚刚使用尖括号替换了圆括号(如(int)settings["timeout"]中所示),但没有获得额外的类型安全性,因为您可以自由地执行此操作

var timeout = settings<int>["connectionString"];

如果你有强烈但不是静态类型的东西,你可能要等到C#4.0及其动态关键字。

答案 6 :(得分:0)

在最近的C-sharp中,您可以将返回类型声明为&#34; dynamic&#34;。这与使用&#34; object&#34;相同。除了C#运行时允许你在代码中使用它,就好像它是你认为的那样,然后在运行时检查以确保你是对的......