不允许重载泛型类型参数?

时间:2012-03-08 15:37:15

标签: c# .net generics clr

这是好奇心和部分原因,因为我只是想尝试使用它。如果您具有以下定义,则编译器不允许这样做,因为它表示已定义成员。不允许泛型类型参数的独占重载的原因是什么?

void Get<T>() where T: struct {}
void Get<T>() where T: class {}

在我看来,这没有固有的问题。有人可能会争辩说,在定义重叠的情况下,编制者应该选择哪个并不总是很清楚(但是普通分辨率似乎是最具体的匹配)。

有人可以帮助我理解或指出资源禁止这种情况的原因是什么?

2 个答案:

答案 0 :(得分:9)

Eric Lippert已经在关于通用约束和方法签名的博客文章中回答了这个问题:http://blogs.msdn.com/b/ericlippert/archive/2009/12/10/constraints-are-not-part-of-the-signature.aspx

泛型类型的约束不是CLR中方法签名的一部分,因此您不能有两种方法仅在泛型类型约束方面有所不同。如果没有CLR支持,让C#以一种与其他.NET语言兼容的合理方式支持这些将是非常繁琐的。

答案 1 :(得分:1)

structNullable<T>的约束是恕我直言,真的很不幸。像Nullable<String>Nullable<Nullable<Nullable<int>>>这样的东西可能会浪费,但那又怎样呢?将前者作为其内容;取消将其作为内容取消,如果内容为非空,则设置HasValue。如果所有nullables报告int,则将前者列为HasValue,并且当取消装箱时,如果内容为非null,则设置所有嵌套项目的HasValue

否则,我建议您创建一个类型为T的静态泛型类,其中包含一个委托属性,该属性接受T作为参数。该属性应返回应初始化的私有字段的内容,以指向将检查T类型的方法,并将委托设置为structclass版本为合适的。

这是我正在谈论的一个样本;这个使用各种接口约束而不是结构/类约束,但同样的原则可以同样有效地使用。

        static class _FooDispatcher<T>
        {
            public static Action<T> Foo = setupFoo;

            static void doFooWithIGoodFoo<TT>(TT param) where TT : IGoodFoo
            {
                Console.WriteLine("Dispatching as IGoodFoo with {1} type {0}", typeof(TT).ToString(), typeof(TT).IsValueType ? "value" : "reference");
                param.Foo();
            }
            static void doFooWithIOkayFoo<TT>(TT param) where TT : IOkayFoo
            {
                Console.WriteLine("Dispatching as IOkayFoo with {1} type {0}", typeof(TT).ToString(), typeof(TT).IsValueType ? "value" : "reference");
                param.Foo();
            }
            static void doFooSomehow<TT>(TT param)
            {
                Console.WriteLine("Nothing exciting with {1} type {0}", typeof(TT).ToString(), typeof(TT).IsValueType ? "value" : "reference");
            }
            static void setupFoo(T param)
            {
                System.Reflection.MethodInfo mi;
                if (typeof(IGoodFoo).IsAssignableFrom(typeof(T)))
                    mi = typeof(_FooDispatcher<T>).GetMethod("doFooWithIGoodFoo", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
                else if (typeof(IOkayFoo).IsAssignableFrom(typeof(T)))
                    mi = typeof(_FooDispatcher<T>).GetMethod("doFooWithIOkayFoo", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
                else
                    mi = typeof(_FooDispatcher<T>).GetMethod("doFooSomehow", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
                Foo = (Action<T>)(@Delegate.CreateDelegate(typeof(Action<T>), mi.MakeGenericMethod(typeof(T))));
                Foo(param);
            }
        }