我不会给这项工作:
public interface ICallBack
{
void Handle<T>(T arg);
}
public class MessageHandler : ICallBack
{
public void Handle<T>(T arg)
{
string name = typeof(T).Name;
Console.WriteLine(name);
}
public void Handle(int arg)
{
string name = "wow, an int";
Console.WriteLine(name);
}
}
public class Worker
{
public void DoSomething(ICallBack cb)
{
cb.Handle(55);
}
}
//...
Worker foo = new Worker();
ICallBack boo = new MessageHandler();
//I want this to print "Wow, an int"
foo.DoSomething(boo)
Run Code Online (Sandbox Code Playgroud)
不幸的是,它调用通用入口点而不是"专用"入口点.好吧,那就是你的接口.
我也尝试过相同的方法,但用特定的通用签名替换特定于int的签名Mojo:
public void Handle<T>(T arg) where T : Mojo {}
Run Code Online (Sandbox Code Playgroud)
如果参数是类型的话,我希望这足以形成一个"特殊覆盖" Mojo.但是现在编译器抱怨我有两个具有相同签名的方法(一个是Mojo特定的,另一个是开放的).好吧,我实际上希望它会认为它是"相同的签名",这样两者都可以实现界面,并且在运行时选择"最佳".呃,好吧.
实际上,我试图实现与"Traits"模糊地相似,这就是" C++的其他用户 ".我想它也可以被认为是"界面签名逆变"的一种形式.
我很想发现有一个特殊的C#关键字可以启用此功能,或者它是.net 4.5中C#的特色添加.
是的,不是吗?评论?
不,这是不可能的.
当编译器编译实现接口的类型时,它将创建一个接口映射,详细说明链接到接口的每个方法的类型的哪些方法.这不能在运行时随意更改.
这意味着无论何时Handle通过该接口调用方法,它总是会在基础类型上使用相同的方法,而不管您认为哪种方法更合适.
如果您希望底层类型在内部调用特定方法,则根据泛型参数的特定类型,您必须自己实现,使用动态分派,或使用if语句或类似方法来检测哪种类型的T拥有并调用适当的方法.
这里的答案说你可以强制转换你调用方法的类型,dynamic意味着你正在使用反射来完全绕过接口.对于这个特定场景,接口可能根本没有任何方法,转换为dynamic仍然"工作".
我不推荐这种方法.您正在有效地编写代码,假设它具有对所有底层类型方法的全权访问权限,即使它特别说"我只需要此接口".
另外,如果唯一的目标是避免运行时错误,请考虑如果在类中显式实现该方法会发生什么:
void Main()
{
Worker foo = new Worker();
ICallBack boo = new MessageHandler();
foo.DoSomething(boo);
}
public interface ICallBack
{
void Handle<T>(T arg);
}
public class MessageHandler : ICallBack
{
void ICallBack.Handle<T>(T arg)
{
string name = typeof(T).Name;
Console.WriteLine(name);
}
}
public class Worker
{
public void DoSomething(ICallBack cb)
{
((dynamic)cb).Handle(55);
}
}
Run Code Online (Sandbox Code Playgroud)
这将在运行时崩溃:
RuntimeBinderException:
'UserQuery.MessageHandler'不包含'Handle'的定义
您可以在LINQPad中测试上面的代码.
| 归档时间: |
|
| 查看次数: |
420 次 |
| 最近记录: |