Вызов метода по умолчанию интерфейса C# из реализации структуры без упаковки
Единственное, что я могу придумать, это следующее, что далеко от идеала:
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();
}
}
Есть ли более простой способ сделать это?
(Связано и как я добрался до этого вопроса: Вызов метода по умолчанию интерфейса C# из реализации класса)
2 ответа
Я не думаю, что есть какие-то ассигнования. Этот ответ на этот, возможно, повторяющийся вопрос объясняет, что JIT-компилятор во многих случаях может избегать боксов, включая явные вызовы реализации интерфейса. Энди Айерс из команды JIT подтвердил это в комментарии и предоставил ссылку на PR, который это реализовал.
Я адаптировал код в этом ответе:
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;
}
}
}
Результаты не показывают распределения:
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 | - | - | - | - |
Я изменил тип возвращаемого значения на int, как и связанный ответ, чтобы гарантировать, что метод не будет оптимизирован.
Я еще не настроился на C# 8.0, поэтому я не уверен, что это сработает, но вот идея, которую вы можете попробовать:
struct Baz : IBar
{
public void CallFoo()
{
this.AsBar().Foo();
}
public IBar AsBar()
{
return this;
}
}