Выделяет ли передача структуры в поле интерфейса?
У меня есть структура вроде этого
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