Calling C# interface default method from implementing struct without boxing

不想你离开。 提交于 2019-12-12 14:57:19

问题


The only thing I can think of is as follows, which is far from ideal:

interface IBar {
    void Foo() => Console.WriteLine("Hello from interface!");
}

struct Baz : IBar {
    // compiler error
    void Test1() => this.Foo();

    // IIRC this will box
    void Test2() => ((IBar)this).Foo();

    // this shouldn't box but is pretty complicated just to call a method
    void Test3() {
        impl(ref this);

        void impl<T>(ref T self) where T : IBar
            => self.Foo();  
    }
}

Is there a more straightforward way to do this?

(Related and how I got to this question: Calling C# interface default method from implementing class)


回答1:


I don't think there are any allocations. This answer to this possibly duplicate question explains that the JIT compiler can avoid boxing in many cases, including explicit interface implementation calls. Andy Ayers from the JIT team verified this in a comment and provided a link to the PR that implemented this.

I adapted the code in that answer :

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;
        }
    }

}

The results don't show any allocations :


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 |     - |     - |     - |         - |

I changed the return type to an int just like the linked answer to ensure the method won't be optimized away




回答2:


Haven't set myself up for c# 8.0 yet, so I'm not sure this'll work, but here's an idea you could try:

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

    public IBar AsBar()
    {
        return this;
    }
}


来源:https://stackoverflow.com/questions/57827493/calling-c-sharp-interface-default-method-from-implementing-struct-without-boxing

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!