在不装箱的情况下从实现struct调用C#接口默认方法

在不装箱的情况下从实现struct调用C#接口默认方法,c#,c#-8.0,default-interface-member,C#,C# 8.0,Default Interface Member,我能想到的唯一一件事是,这离理想还很远: 接口IBar{ void Foo()=>Console.WriteLine(“来自接口的你好!”); } 结构Baz:IBar{ //编译错误 void Test1()=>this.Foo(); //这是一个盒子 void Test2()=>((IBar)this.Foo(); //这不应该是一个方框,但是仅仅调用一个方法就相当复杂了 void Test3(){ impl(参考本文件); 无效impl(参考T self),其中T:IBar =>self.

我能想到的唯一一件事是,这离理想还很远:

接口IBar{
void Foo()=>Console.WriteLine(“来自接口的你好!”);
}
结构Baz:IBar{
//编译错误
void Test1()=>this.Foo();
//这是一个盒子
void Test2()=>((IBar)this.Foo();
//这不应该是一个方框,但是仅仅调用一个方法就相当复杂了
void Test3(){
impl(参考本文件);
无效impl(参考T self),其中T:IBar
=>self.Foo();
}
}
有没有更直接的方法


(相关以及我是如何回答这个问题的:)

我还没有为c#8.0做好准备,所以我不确定这是否可行,但有一个想法你可以试试:

struct Baz : IBar
{
    public void CallFoo()
    {
        this.AsBar().Foo();
    }

    public IBar AsBar()
    {
        return this;
    }
}

我认为没有任何分配。对此,JIT编译器可以在许多情况下避免装箱,包括显式接口实现调用。JIT团队的安迪·艾尔斯(Andy Ayers)在评论中对此进行了验证,并将其提供给了实施该计划的公关

我修改了答案中的代码:

using System;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

namespace DIMtest
{
    interface IBar {
        int Foo(int i) => i;
    }

    struct Baz : IBar {
        //Does this box?        
        public int  Test2(int i) => ((IBar)this).Foo(i);
    }


    [MemoryDiagnoser, CoreJob,MarkdownExporter]
    public class Program
    {
        public static void Main() => BenchmarkRunner.Run<Program>();

        [Benchmark]
        public int ViaDIMCast()
        {
            int sum = 0;
            for (int i = 0; i < 1000; i++)
            {
                sum += (new Baz().Test2(i));
            }

            return sum;
        }
    }

}

我将返回类型更改为int,就像链接的答案一样,以确保方法不会被优化掉

@GSerg,但将valuetype强制转换到接口会将其装箱,这里就是这种情况。我将
结构
过重。你是。不过,演员阵容还是需要的。@GSerg啊,好吧,那太不幸了。我曾希望(ab)使用DIMs作为结构缺失继承的替代方案,但如果涉及到这么多开销,我想我会放弃它。无论如何,谢谢你的回答。我还没有深入研究这个新特性,但是完全不实现这个方法怎么样?然后
bazInstance.Foo()
应该调用没有框的方法。@JoelCoehoorn。我不反对downvote,但是downvoter,请帮助我理解问题所在,以便我可以了解。我没有downvote,但您继承的是无效的非接口(除非它在C#8.0中)。在OP的示例中
Bar
是接口的名称。就我个人而言,我会称之为IBar。那可能是因为
AsBar
方法仍然与界面紧密相连。我不能代表投票人说话,但我猜他们发现你的答案有两个地方不对劲,至少:1)你的答案是推测性的,而问题的作者应该得到真正的答案,一定要解决他们的问题,2)在我看来,你的答案很可能最终会装箱
Baz
值,这正是OP试图避免的。Neat,我不知道.NET core做了那些优化。实际上,我手边没有准备好C#8编译器,所以我用隐式实现和.NET framework对其进行了测试。可悲的是,一个人没有优化掉拳击。我将不得不尝试一下,看看优化是否有保证。谢谢你找到了答案。如果DIM的行为与隐式接口实现相同,那么您对复制的看法可能是正确的。@Velocirobtor.NET Core和.NET。。。老年人与老年人大不相同。相关问题表明,自Core2.1以来,显式接口实现得到了优化。DIM依赖于核心2.0运行时功能,我怀疑其中许多功能都涉及优化。如上所述,jit可以省略一些框,前提是框的创建和使用对jit都可见,并且框在IL中不是
dup
d。。。在Core中,异步状态机核心逻辑现在依赖于此。其中一些选项已经回到了完整的框架,例如4.8也应该能够做到这一点。我们仍然可以在这里改进。。。

BenchmarkDotNet=v0.11.5, OS=Windows 10.0.18956
Intel Core i7-3770 CPU 3.40GHz (Ivy Bridge), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=3.0.100-preview9-014004
  [Host] : .NET Core 3.0.0-preview9-19423-09 (CoreCLR 4.700.19.42102, CoreFX 4.700.19.42104), 64bit RyuJIT
  Core   : .NET Core 3.0.0-preview9-19423-09 (CoreCLR 4.700.19.42102, CoreFX 4.700.19.42104), 64bit RyuJIT

Job=Core  Runtime=Core  

|     Method |     Mean |    Error |   StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
|----------- |---------:|---------:|---------:|------:|------:|------:|----------:|
| ViaDIMCast | 618.5 ns | 12.05 ns | 13.40 ns |     - |     - |     - |         - |