Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/259.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 通用传递接口。这可能吗?_C#_Generics - Fatal编程技术网

C# 通用传递接口。这可能吗?

C# 通用传递接口。这可能吗?,c#,generics,C#,Generics,我不愿意做这项工作: 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); } publi

我不愿意做这项工作:

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)
我希望如果参数的类型是
Mojo
,这将足以形成一个“特殊覆盖”。但是现在编译器抱怨我有两个具有相同签名的方法(一个是
Mojo
specific,另一个是开放式的)。嗯,我实际上希望它会认为它是“相同的签名”,以便两者都能实现接口,并在运行时选择“最佳”。好吧

事实上,我试图达到的目标与“特质”大致相似,即“特质”。我想它也可以被视为一种“接口签名冲突”

我很想发现有一个特殊的C#关键字支持此功能,或者它是.NET4.5中C#的一个特色添加


是,不是?注释?

尝试将您的
工作者
类更改为:

public class Worker
{
    public void DoSomething(ICallBack cb)
    {
        ((dynamic)cb).Handle(55);
    }
}
[编辑]

正如您所知,添加看起来无害的“动态”会严重更改输出代码。它在运行时有效地调用编译器来执行动态操作

我还提请大家注意这里的评论和其他答案。我建议你阅读它们并理解为什么做上述事情可能不是一个好主意

此外,如下面的回答所述,如果显式实现了
Handle()
方法,则将参数类型约束为
ICallBack
仍将允许运行时错误

以下是该简单外观方法的IL:

.method public hidebysig instance void DoSomething(class ConsoleApplication1.ICallBack cb) cil managed
{
    .maxstack 9
    .locals init (
        [0] class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo[] CS$0$0000)
    L_0000: nop 
    L_0001: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, int32>> ConsoleApplication1.Worker/<DoSomething>o__SiteContainer0::<>p__Site1
    L_0006: brtrue L_0058
    L_000b: ldc.i4 256
    L_0010: ldstr "Handle"
    L_0015: ldnull 
    L_0016: ldtoken ConsoleApplication1.Worker
    L_001b: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    L_0020: ldc.i4.2 
    L_0021: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
    L_0026: stloc.0 
    L_0027: ldloc.0 
    L_0028: ldc.i4.0 
    L_0029: ldc.i4.0 
    L_002a: ldnull 
    L_002b: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_0030: stelem.any [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
    L_0035: ldloc.0 
    L_0036: ldc.i4.1 
    L_0037: ldc.i4.3 
    L_0038: ldnull 
    L_0039: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_003e: stelem.any [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
    L_0043: ldloc.0 
    L_0044: call class [System.Core]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::InvokeMember(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, string, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [mscorlib]System.Type>, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)
    L_0049: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, int32>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
    L_004e: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, int32>> ConsoleApplication1.Worker/<DoSomething>o__SiteContainer0::<>p__Site1
    L_0053: br L_0058
    L_0058: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, int32>> ConsoleApplication1.Worker/<DoSomething>o__SiteContainer0::<>p__Site1
    L_005d: ldfld !0 [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, int32>>::Target
    L_0062: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, int32>> ConsoleApplication1.Worker/<DoSomething>o__SiteContainer0::<>p__Site1
    L_0067: ldarg.1 
    L_0068: ldc.i4.s 12
    L_006a: callvirt instance void [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, int32>::Invoke(!0, !1, !2)
    L_006f: nop 
    L_0070: ret 
}
.method public hidebysing实例void DoSomething(类ConsoleApplication1.ICallBack cb)cil托管
{
.maxstack 9
.init(
[0]类[Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo[]CS$0$0000)
L_0000:没有
L_0001:ldsfld类[System.Core]System.Runtime.CompilerServices.CallSite`1控制台应用程序1.Worker/o_SiteContainer0::p_Site1
L_0006:brtrue L_0058
L_000b:ldc.i4 256
L_0010:ldstr“手柄”
L_0015:ldnull
L_0016:ldtoken控制台应用程序1.工作者
L_001b:调用类[mscorlib]System.Type[mscorlib]System.Type::GetTypeFromHandle(valuetype[mscorlib]System.RuntimeTypeHandle)
L_0020:ldc.i4.2
L_0021:newarr[Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
L_0026:stloc.0
L_0027:ldloc.0
L_0028:ldc.i4.0
L_0029:ldc.i4.0
L_002a:ldnull
L_002b:调用类[Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo[Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(值类型[Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,字符串)
L_0030:stelem.any[Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
L_0035:ldloc.0
L_0036:ldc.i4.1
L_0037:ldc.i4.3
L_0038:ldnull
L_0039:调用类[Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo[Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(值类型[Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,字符串)
L_003e:stelem.any[Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
L_0043:ldloc.0
L_0044:调用类[System.Core]System.Runtime.CompilerServices.CallSiteBinder[Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::InvokeMember(valuetype[Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags,string,class[mscorlib]System.Collections.Generic.IEnumerable`1,class[mscorlib]System.Type,class[mscorlib]System.Collections.Generic.IEnumerable`1)
L_0049:调用类[System.Core]System.Runtime.CompilerServices.CallSite`1[System.Core]System.Runtime.CompilerServices.CallSite`1::Create(类[System.Core]System.Runtime.CompilerServices.CallSiteBinder)
L_004e:stsfld类[System.Core]System.Runtime.CompilerServices.CallSite`1控制台应用程序1.Worker/o_SiteContainer0::p_Site1
L_0053:br L_0058
L_0058:ldsfld类[System.Core]System.Runtime.CompilerServices.CallSite`1控制台应用程序1.Worker/o_SiteContainer0::p_Site1
L_005d:ldfld!0[System.Core]System.Runtime.CompilerServices.CallSite`1::Target
L_0062:ldsfld类[System.Core]System.Runtime.CompilerServices.CallSite`1控制台应用程序1.Worker/o_SiteContainer0::p_Site1
L_0067:ldarg.1
L_0068:ldc.i4.s 12
L_006a:callvirt实例无效[mscorlib]系统。操作'3::调用(!0,!1,!2)
L_006f:没有
L_0070:ret
}

不,这是不可能的

当编译器编译实现接口的类型时,它将创建一个接口映射,详细说明该类型的哪些方法链接到接口的每个方法。这不能在运行时随意更改

这意味着,无论何时通过该接口调用
Handle
方法,它都会转到底层类型上的同一方法,而不管您认为任何其他方法更合适

如果希望基础类型根据泛型参数的特定类型在内部调用特定方法,则必须自己实现,可以使用动态分派,也可以使用If语句或类似语句来检测所使用的T的类型并调用相应的方法

这里的答案是,您可以将调用该方法的类型强制转换为
dynamic
,这意味着您正在使用反射一起绕过接口。对于这个特定的场景,界面可能根本没有任何方法,转换到
动态
仍将“工作”

我不推荐这种方法。实际上,您编写的代码假定它对底层类型的所有方法都有全权访问权,即使它明确表示“我只需要这个接口”

另外,如果唯一的目标是避免运行时错误,那么考虑如果在类中显式实现该方法会发生什么:

.method public hidebysig instance void DoSomething(class ConsoleApplication1.ICallBack cb) cil managed
{
    .maxstack 9
    .locals init (
        [0] class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo[] CS$0$0000)
    L_0000: nop 
    L_0001: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, int32>> ConsoleApplication1.Worker/<DoSomething>o__SiteContainer0::<>p__Site1
    L_0006: brtrue L_0058
    L_000b: ldc.i4 256
    L_0010: ldstr "Handle"
    L_0015: ldnull 
    L_0016: ldtoken ConsoleApplication1.Worker
    L_001b: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    L_0020: ldc.i4.2 
    L_0021: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
    L_0026: stloc.0 
    L_0027: ldloc.0 
    L_0028: ldc.i4.0 
    L_0029: ldc.i4.0 
    L_002a: ldnull 
    L_002b: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_0030: stelem.any [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
    L_0035: ldloc.0 
    L_0036: ldc.i4.1 
    L_0037: ldc.i4.3 
    L_0038: ldnull 
    L_0039: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)
    L_003e: stelem.any [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
    L_0043: ldloc.0 
    L_0044: call class [System.Core]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::InvokeMember(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, string, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [mscorlib]System.Type>, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)
    L_0049: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, int32>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
    L_004e: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, int32>> ConsoleApplication1.Worker/<DoSomething>o__SiteContainer0::<>p__Site1
    L_0053: br L_0058
    L_0058: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, int32>> ConsoleApplication1.Worker/<DoSomething>o__SiteContainer0::<>p__Site1
    L_005d: ldfld !0 [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, int32>>::Target
    L_0062: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, int32>> ConsoleApplication1.Worker/<DoSomething>o__SiteContainer0::<>p__Site1
    L_0067: ldarg.1 
    L_0068: ldc.i4.s 12
    L_006a: callvirt instance void [mscorlib]System.Action`3<class [System.Core]System.Runtime.CompilerServices.CallSite, object, int32>::Invoke(!0, !1, !2)
    L_006f: nop 
    L_0070: ret 
}
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);
    }
}