Visual studio 2010 C#编译器允许接口代替泛型派生版本?
我对编译器中一些我不理解的行为有点困惑。我将其简化为以下代码示例:Visual studio 2010 C#编译器允许接口代替泛型派生版本?,visual-studio-2010,c#-4.0,.net-2.0,Visual Studio 2010,C# 4.0,.net 2.0,我对编译器中一些我不理解的行为有点困惑。我将其简化为以下代码示例: public interface IFoo { } public interface IBar<T> : IFoo { } public delegate void DHandler<T>(IBar<T> arg); public static class Demo { static void Garply<T>(DHand
public interface IFoo { }
public interface IBar<T> : IFoo { }
public delegate void DHandler<T>(IBar<T> arg);
public static class Demo
{
static void Garply<T>(DHandler<T> handler) { }
public static void DoStuffWithInt()
{
Garply<int>(Handler);
}
static void Handler(IFoo arg) { }
}
公共接口IFoo{}
公共接口IBar:IFoo{}
公共代表无效DHandler(IBar arg);
公共静态类演示
{
静态void-Garply(DHandler处理程序){}
公共静态void dostufwithint()
{
加普利(装卸工);
}
静态void处理程序(IFoo arg){}
}
我的问题是,我不希望代码能够编译,但它确实可以。我不希望它编译,因为DHandler
需要签名中的IBar
,但是Handler
方法声明IFoo
,这不是IBar
(尽管相反)。因此,Handler
不是DHandler
,因此它的委托不能用作Garply
调用的参数
如果我将代码更改为readHandler(IBar arg)
它将编译。如果我将其更改为readHandler(IBar arg)
则不会。这两种行为都是我所期望的
提示这个问题的实际问题是,当签名是Handler(IBar arg)
时,编译器会抱怨我需要显式指定Garply
调用的类型参数。在本例中,这很平常,但在实际代码中,这将是一个真正的麻烦。我感到困惑,因为Garply
的参数是一个带有签名(IBar arg)
的方法,所以它的委托人将是DHandler
,因此选择的Garply
将毫无疑问地是Garply
。但显然,编译器发现了一个歧义。它正在调查,这让我陷入了上面的困惑,我只能猜测,也许编译器在想“好吧,让Jason吃惊的是,我会接受一个IFoo
,因为这个IBar
,所以必须指定一个T
,让我知道我应该把它编译成IBar
,而不是IFoo
”. 这也许可以解释为什么它需要类型参数。但是有人能解释一下吗?这是委托差异,它是在C#2中引入的。这与C#4中引入的通用方差不同
这里有一个更简单的例子:
delegate void Foo(string x);
class Test
{
static void Main()
{
Foo foo = Bar;
}
static void Bar(object y) {}
}
关键是我们可以从Bar
方法创建Foo
委托的实例,因为Bar
只要给定任何对象
,就可以工作。当调用Foo
委托时,它将始终提供string
引用,并且存在从string
到object
的引用转换。因此,如果我有:
Foo f = ...;
f("fred");
。。。该调用始终适用于Bar
同样,在您的情况下,Garply
使用handler
进行的任何调用都肯定是对handler
的有效调用-因此编译器很乐意创建一个适当的DHandler
实例
当
Handler
只接受IBar
时,问题在于编译器在推断类型参数时没有对参数使用可能的方法组转换。这是一个类型推断肯定会更强的领域,事实上它在一个非常相似的领域得到了改进,尽管我永远记不起细节——在C#3和C#4之间。msdn.microsoft.com/en us/library/ms173174(v=vs.110)。aspxAh,因此委托问题是一个无关的红鲱鱼。在我的问题中,我假设该参数将使用委托协方差,但我应该预期反向方差。恐怕我从来没有实际使用过逆变或任何代理逆变,所以这对我来说是陌生的。我的坏-明天会预约让我的大脑旋转180度!至于我最初的问题——所以对于人类来说,类型是什么是显而易见的,我们可以想象编译器“应该”很容易看到它,但事实并非如此。公平地说,我会努力重新规划自己的道路。谢谢