2009-07-31 5 views
2

Рассмотрим следующий сценарий:Тип обертки в .NET: struct или class?

int Caller1<T>(T t) where T : IInterface {...} 
T Caller2<T>() where T : IInterface {...} 

class Wrappee // doesn't implement IInterface, but could 

??? Wrapper : IInterface { 
    private readonly Wrappee _wrappee; 

    // methods call _wrappee's methods 
} 

Теперь общие рекомендации по выбору между struct и class является «использовать struct если вам нужно семантику значений и class для ссылочных семантики». Семантика, которая нам нужна, это «ссылка на Wrappee». Но, похоже, мы все равно можем сделать Wrapper struct: копирование его значения - то же самое, что и копирование ссылки Wrappee, и копии будут иметь ссылку на тот же объект! Накладные расходы ниже, и scalar replacement может уменьшить его до нуля для локальных переменных. Похоже, что можно назвать даже мутирующие методы на _wrappee.

Я ничего не пропустил? Есть ли веская причина сделать класс Wrapper?

Существует один, если абонент не является универсальным:

int Caller(IInterface t) {...} 

В этом случае Wrapper должен быть классом, чтобы избежать бокс.

Примечание для тех, кто знает Haskell: Я пытаюсь найти ближайший .NET-аналог до newtype.

ОБНОВЛЕНИЕ: см. Professional .NET 2.0 Generics и Peter Ritchie on MSDN forums за отсутствие бокса в первом случае.

+0

Почему, по-вашему, использование структуры в качестве параметра типового типа может повлиять на необходимость бокса? –

+0

См. Обновление. –

ответ

2

Часто ваш класс/структура будет храниться или передаваться внутренне с помощью методов, которые вы вызываете (вы не показывали, что Caller1 и Caller2 делают), и в этом случае он, вероятно, получит коробку. Возможно, чаще, чем вы ожидали. Поэтому, если вы не сможете доказать, что структура будет более эффективной: не беспокойтесь и просто придерживайтесь класса.

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

Однако, если производительность действительно беспокойство, и если вы можете гарантировать, что экземпляры передаются только в качестве параметра с родовым типом ограничением, и никогда не хранятся в интерфейсе типизированных полея или коллекциях, текущее встраивание из структур по времени выполнения .NET будет более эффективным, так как ваша структура-обертка будет в основном оптимизирована. Но это много, если.

0

Я бы сказал класс, потому что вы инкапсулируете поведение, а не только данные.

4

Да, поскольку вы будете обращаться к обертке с помощью переменной IInterface, чтобы избежать бокса, это должен быть класс.

EDIT: Если вы обращаетесь к обертке с помощью переменной, напечатанной как Wrapper, и обращаетесь к методам Wrapper, а не к методам IInterface, то структура является прекрасной.

+0

Я не обращаюсь к нему с помощью переменной 'IInterface', но является общим параметром, ограниченным для вывода из' IInterface'. См. Обновление. –

+0

То есть код вызова выглядит так: 'Wrapper y = Caller2(); return Caller1 (y); ' –