В .NET, если вы передадите структуру в метод с параметром интерфейса, будет ли в нем значение? - PullRequest
1 голос
/ 19 марта 2011

Из простого теста я вижу, что если вы передаете структуру в метод, она передается по значению, но если вы сначала присваиваете ее интерфейсу, она передается по ссылке.

interface IFoo { int Val { get; set; } }
struct Foo : IFoo { public int Val { get; set; } }

void Bar(IFoo foo) { foo.Val = 1; }

Foo foo = new Foo();
IFoo ifoo = new Foo();

Bar(foo);
Bar(ifoo);

Console.WriteLine(foo.Val);  // 0, passed by value
Console.WriteLine(ifoo.Val); // 1, passed by ref

Итак, мой вопрос, есть ли еще операция по переносу для передачи структуры, подобной этой?

Ответы [ 2 ]

5 голосов
/ 19 марта 2011

Всякий раз, когда структура преобразуется в интерфейс, она упаковывается.

Foo foo = new Foo();//Doesn't box yet
IFoo ifoo = new Foo();//Boxes

Bar(foo);//creates a new boxed copy
Bar(ifoo);//Uses the old boxed version created in line 2

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

void Bar<T>(T foo)
    where T:IFoo 
{
}

При этом используется тот факт, что дженерики становятся специализированными для каждого типа значения.


Но если вы следуете руководству по проектированию, что изменяемые структуры являются злом и, таким образом, делают вашу структуру неизменной, это не имеет большого значения, есликодовые поля или нет.В этом случае бокс вызывает лишь незначительное снижение производительности, но не сильно меняет семантику.

0 голосов
/ 19 марта 2011

Все интерфейсы являются ссылочными типами, поэтому бокс происходит на линии

IFoo ifoo = new Foo();

, а не при вызове Bar.

...