views:

170

answers:

3

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.

A: 

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

Joel B Fant
+4  A: 

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.

Charles Bretana
I don't access it via an `IInterface` variable, but a generic parameter constrained to derive from `IInterface`. See the update.
Alexey Romanov
That is, calling code looks like:`Wrapper y = Caller2(); return Caller1(y);`
Alexey Romanov
+1  A: 

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.

Ruben