c# – 除了通用类之外,还有其他方法可以调用没有框架的结构的接
看代码片段
public interface I0 { void f0(); } public struct S0:I0 { void I0.f0() { } } public class A<E> where E :I0 { public E e; public void call() { e.f0(); } } 这里是调用()的IL代码 .maxstack 8 L_0000: ldarg.0 L_0001: ldflda !0 Temp.A`1<!E>::e L_0006: constrained !E L_000c: callvirt instance void Temp.I0::f0() L_0011: ret 参见constrained
这意味着它将调用一个包含f0的接口方法代码的方法,而不需要结构化. 做任何其他方法没有拳击存储的接口方法如上面的GenericClass在C#中? 解决方法
它取决于…你具体说你不想要一个泛型类…唯一的其他选项是非泛型类中的通用方法.唯一的其他时间,你可以让编译器发出一个受限制的调用,如果你在一个结构体上调用ToString(),GetHashCode()或Equals()(from(object)),因为那些被约束 – 如果struct有一个覆盖会打电话如果没有覆盖,它们将被调用.这就是为什么你应该总是重写这3个结构体; p但是我离题.一个简单的例子将是一个使用一些静态方法的实用程序类 – 扩展方法将是一个理想的例子,因为您也可以获得编译器在公共/隐式API和扩展/显式API之间自动切换的优点,而无需您更改代码.例如,以下(显示隐式和显式实现)都没有拳击,一个调用和一个约束的callvirt,它将通过JIT调用实现:
using System; interface IFoo { void Bar(); } struct ExplicitImpl : IFoo { void IFoo.Bar() { Console.WriteLine("ExplicitImpl"); } } struct ImplicitImpl : IFoo { public void Bar() {Console.WriteLine("ImplicitImpl");} } static class FooExtensions { public static void Bar<T>(this T foo) where T : IFoo { foo.Bar(); } } static class Program { static void Main() { var expl = new ExplicitImpl(); expl.Bar(); // via extension method var impl = new ImplicitImpl(); impl.Bar(); // direct } } 这里是IL的关键点: .method private hidebysig static void Main() cil managed { .entrypoint .maxstack 1 .locals init ( [0] valuetype ExplicitImpl expl,[1] valuetype ImplicitImpl impl) L_0000: ldloca.s expl L_0002: initobj ExplicitImpl L_0008: ldloc.0 L_0009: call void FooExtensions::Bar<valuetype ExplicitImpl>(!!0) L_000e: ldloca.s impl L_0010: initobj ImplicitImpl L_0016: ldloca.s impl L_0018: call instance void ImplicitImpl::Bar() L_001d: ret } .method public hidebysig static void Bar<(IFoo) T>(!!T foo) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() .maxstack 8 L_0000: ldarga.s foo L_0002: constrained. !!T L_0008: callvirt instance void IFoo::Bar() L_000d: ret } 扩展方法的一个不足之处在于,它正在堆栈上执行一个额外的结构体(见ldloc.0)副本,如果它是超大的,或者它是一个变异的方法(可能是一个问题)你应该避免反过来).如果是这种情况,ref参数是有帮助的,但请注意,扩展方法不能具有参考参数 – 因此您不能使用扩展方法.但请考虑: Bar(ref expl); Bar(ref impl); 有: static void Bar<T>(ref T foo) where T : IFoo { foo.Bar(); } 这是: L_001d: ldloca.s expl L_001f: call void Program::Bar<valuetype ExplicitImpl>(!!0&) L_0024: ldloca.s impl L_0026: call void Program::Bar<valuetype ImplicitImpl>(!!0&) 有: .method private hidebysig static void Bar<(IFoo) T>(!!T& foo) cil managed { .maxstack 8 L_0000: ldarg.0 L_0001: constrained. !!T L_0007: callvirt instance void IFoo::Bar() L_000c: ret } 仍然没有拳击,但现在我们也不会复制结构,即使是明确的情况. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |