c# – 除了通用类之外,还有其他方法可以调用没有框架的结构的接口方法吗?

前端之家收集整理的这篇文章主要介绍了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

The constrained prefix can also be used for invocation of interface methods on value types,because the value type method implementing the interface method can be changed using a MethodImpl. If the constrained prefix is not used,the compiler is forced to choose which of the value type’s methods to bind to at compile time. Using the constrained prefix allows the MSIL to bind to the method that implements the interface method at run time,rather than at compile time.

这意味着它将调用一个包含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 
}

仍然没有拳击,但现在我们也不会复制结构,即使是明确的情况.

原文链接:https://www.f2er.com/csharp/95070.html

猜你在找的C#相关文章