在不装箱的情况下从实现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 | - | - | - | - |