Распределяет ли передача структуры в поле интерфейса? - PullRequest
3 голосов
/ 29 ноября 2009

У меня есть что-то вроде структуры

struct MyStructure
    :IFoo
{
}

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

public BarThisFoo(IFoo a)
{

}

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

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

Ответы [ 5 ]

8 голосов
/ 30 ноября 2009

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

struct MyStructure
    :IFoo
{
}

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

}

См. J. Richter CLR через C # , 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
5 голосов
/ 30 ноября 2009

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

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

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

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

5 голосов
/ 29 ноября 2009

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

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

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

1 голос
/ 29 ноября 2009

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

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

1 голос
/ 29 ноября 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...