Выделяет ли передача структуры в поле интерфейса?

У меня есть структура вроде этого

struct MyStructure
    :IFoo
{
}

и такой метод:

public BarThisFoo(IFoo a)
{

}

мой вопрос заключается в передаче структуры в этот метод "box" структуры, что вызывает выделение мусора?

Приложение: Прежде чем кто-либо скажет, сбор мусора в этом приложении не является бесплатным, он действительно очень чувствителен к сборкам мусора, поэтому важно выделять бесплатный код.

Ответы

Ответ 1

Да, да. Бокс происходит всякий раз, когда вы конвертируете из:

  • тип значения для ссылки на объект
  • тип значения для ссылки System.ValueType
  • тип значения для ссылки на интерфейс, реализованный по типу значения
  • тип перечисления в ссылку System.Enum

Это случай III, очевидно. Вы можете прочитать более подробный пример здесь.

Ответ 2

Чтобы избежать бокса, вы можете использовать generics с ограничениями:

struct MyStructure
    :IFoo
{
}

public void BarThisFoo<T>(T a) where T : IFoo
{

}

См. J. Richter CLR через С#, 2-е издание, глава 14: Интерфейсы, раздел "Общие и ограничения интерфейса".

EDIT:

Пример кода

using System;
using System.Collections;

interface IFoo {
    void Foo();
}
struct MyStructure : IFoo {
    public void Foo() {
    }
}
public static class Program {
    static void BarThisFoo<T>(T t) where T : IFoo {
        t.Foo();
    }
    static void Main(string[] args) {
        MyStructure s = new MyStructure();
        BarThisFoo(s);
    }
}

IL-код для метода Main не содержит никаких инструкций в поле:

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       15 (0xf)
  .maxstack  1
  .locals init ([0] valuetype MyStructure s)
  IL_0000:  ldloca.s   s
  IL_0002:  initobj    MyStructure
  IL_0008:  ldloc.0
  IL_0009:  call       void Program::BarThisFoo<valuetype MyStructure>(!!0)
  IL_000e:  ret
} // end of method Program::Main

Ответ 3

Как отмечали другие, да, преобразование структуры в интерфейс, который она реализует, - это бросок бокса. Более важным является не то, что ответ на вопрос, но и то, что вы можете ответить на него сами. Если вы используете ILDASM для демонстрации тестового приложения, вы увидите, что команда "box" генерируется компилятором в точке преобразования. Теперь, в следующий раз, когда у вас возникнет вопрос о боксе, вы можете просто написать себе тестовую программу, разобрать ее, а затем вы узнаете.

Кстати, обратите внимание, что бокс не происходит, если вы вызываете метод неявно реализованного метода интерфейса в struct:

struct S : IFoo { public void Foo() { ... 
...
myS.Foo(); // no boxing
((IFoo)myS).Foo(); // boxing

Это особенно актуально для методов интерфейса для изменяемых типов значений; помните, что если вы мутируете тип бокс-значения, вы мутируете значение в поле, а не переменную, которая первоначально содержала значение в штучной упаковке. Тот факт, что myS.Foo() и ((IFoo) myS).Foo() может иметь другую семантику, является еще одной причиной, по которой изменяемые типы значений являются чистым злом, и их следует избегать.

Ответ 4

Да. Приведение значения к типу интерфейса, которому он соответствует, будет вставлять значение. Для обработки типа значения в качестве объекта требуется операция бокса. Он добавляет необходимые заголовки (включая vtable) к значению, чтобы вы могли вызвать на нем методы интерфейса. Значение в коробке зависит от сбора мусора как любого управляемого объекта.

Ответ 5

Бокс - это процесс преобразования типа значения в объект типа или любого типа интерфейса, реализованного этим типом значения.

Источник: http://msdn.microsoft.com/en-us/library/yz2be5wk.aspx