Alexey Romanov
Alexey Romanov

Reputation: 170775

Wrapper type in .NET: struct or class?

Consider the following scenario:

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
}

Now, the general advice for choosing between struct and class is "use struct if you need value semantics and class for reference semantics". The semantics we need is "reference to Wrappee". But it seems we can still make Wrapper a struct: copying its value is the same is the same as copying a Wrappee reference, and the copies will have a reference to the same object! Overhead is lower and scalar replacement may be able to reduce it to zero for local variables. It seems all right to call even mutating methods on _wrappee.

Am I missing anything? Is there a good reason to make Wrapper a class instead?

There is one if the caller isn't generic:

int Caller(IInterface t) {...}

In this case Wrapper should be a class to avoid boxing.

Remark for those who know Haskell: I am trying to find the closest .NET analogue to newtype.

UPDATE: See Professional .NET 2.0 Generics and Peter Ritchie on MSDN forums for absence of boxing in the first case.

Upvotes: 2

Views: 402

Answers (3)

Ruben
Ruben

Reputation: 15535

Often your class/struct will be stored or passed on internally by methods you call (you didn't show what Caller1 and Caller2 do), and in that case it will probably get boxed. Possibly more often than you expected. So unless you can prove that a struct is going to be way more efficient: don't bother and just stick with a class.

Besides, structs are often frowned upon unless they represent something like a data type, so chosing a class might prevent future discussions of a different nature.

However, if performance is really a concern, and if you can guarantee that instances are only passed as a parameter with a generic type constraint, and never stored in interface-typed fields or collections, the current inlining of structs by the .NET runtime will be more efficient, as your wrapper-struct will mostly be optimized away. But that's a lot of ifs.

Upvotes: 2

Charles Bretana
Charles Bretana

Reputation: 146541

Yes, since you will access wrapper via an IInterface variable, to avoid boxing, it should be a class.

EDIT: If you access wrapper via a variable typed as Wrapper, and access Wrapper methods, not IInterface methods, then a struct is fine.

Upvotes: 4

Joel B Fant
Joel B Fant

Reputation: 24766

I'd say class, because you're encapsulating behavior, not just data.

Upvotes: 0

Related Questions