Jas*_*unt 2 visual-studio-2010 .net-2.0 c#-4.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>(DHandler<T> handler) { }
public static void DoStuffWithInt()
{
Garply<int>(Handler);
}
static void Handler(IFoo arg) { }
}
Run Code Online (Sandbox Code Playgroud)
我的问题是我不希望代码编译,但确实如此.我不希望它编译,因为签名中DHandler<int>需要IBar<int>,但Handler方法声明IFoo,这不是 IBar<int>(虽然反过来是真的).因此Handler不是a DHandler<int>,因此它的委托不能用作Garply<int>调用的参数.
如果我改变代码来读取Handler(IBar<int> arg)它编译.如果我改变它来阅读Handler(IBar<string> arg)它没有.这些行为都是我所期望的.
提示这个问题的实际问题是,当签名是Handler(IBar<int> arg),编译器抱怨我需要显式指定Garply调用的类型参数.在这个例子中是微不足道的,但在实际的代码中,这将是一个真正的麻烦.我很神秘,因为参数Garply是一个带签名的方法(IBar<int> arg),因此它的委托将是一个DHandler<int>,所以选择的Garply<T>将是明确的Garply<int>.但显然编译器看到了歧义.它正在调查,这导致我上面的谜题,我只能猜测,也许编译器正在考虑"好吧,杰森的意外,我已经接受了IFoo这个IBar<T>,所以T必须指定让我知道我应该编译它IBar<T>而不是IFoo".这可能解释了为什么它需要类型参数.但任何人都可以对此有所了解吗?
这是委托方差,这是在C#2.这是引入不一样的通用在C#4引入方差.
这是一个更简单的例子:
delegate void Foo(string x);
class Test
{
static void Main()
{
Foo foo = Bar;
}
static void Bar(object y) {}
}
Run Code Online (Sandbox Code Playgroud)
关键是我们可以Foo从Bar方法中创建委托的实例,因为Bar只要它被赋予任何 就可以工作object.当一个Foo委托被调用时,它将始终提供一个string引用,并且有一个引用转换string为object.所以,如果我有:
Foo f = ...;
f("fred");
Run Code Online (Sandbox Code Playgroud)
......这个电话总是适合的Bar.
同样,在你的情况下,任何呼叫Garply<T>用做handler就绝对是一个有效的电话Handler-这样的编译器是乐于创造一个合适的DHandler<T>实例.
Handler仅接受a 时的问题IBar<int>是,在推断类型参数时,编译器不会对参数使用可能的方法组转换.这是一个类型推断当然可能更强,并且实际上它得到改善的领域 - 在一个非常相似的领域,虽然我永远记不起细节 - 在C#3和C#4之间.
| 归档时间: |
|
| 查看次数: |
87 次 |
| 最近记录: |