views:

330

answers:

5

What is the difference between this:

void MyMethod(IMyInterface value)
{
    //...
}

and this:

void MyMethod<T>(T value) where T : IMyInterface
{
    //...
}
+3  A: 

The generic version will require .NET 2.0.

But seriously, while they look similar, there are fundamental differences between them. One difference is, at runtime, the JIT compiler will generate code for each value type that will be used for the generic version. The non-generic version will require the value types to be boxed in order to be passed to the function.

The difference will also matter when dealing with delegates. The signature of MyMethod<int> matches void MyDelegate(int x) while the non-generic version is not matched.

Mehrdad Afshari
+8  A: 

The main functional difference is that you can know the actual type of the object inside of the generic method. The T parameter will contain the actual type which can advantageous in certain scenarios.

In the non-generic case you cannot guarantee access to the underlying type of the object. Most of the type you could grab value.GetType() but the user could pass Null and thwart you.

JaredPar
This is incorrect, he is constraining T to be an IMyInterface.
joshperry
@joshperry, yes but T will still point to the actual type of the value passed in. More accurately it will point to the type of the reference at the callsite of the method. I am 100% percent confident that I am correct on this point.
JaredPar
Yes, of course I misread your statement. I apologize.
joshperry
Well, 98 % ;-p If the caller has used *implict* generic type inference, then T will be the type of the *variable* (not necessarily the reference, since the reference could be a subclass). If the caller has used *explicit* notation, then again, then they could have different variable, T and instance.
Marc Gravell
@joshperry, no apology needed. Last night I spent a good 10 minutes typing up a full page answer to a question with several examples. Joel then pointed out I misread the question and provided an answer to a different problem. I ended up keeping the answer as a WIKI
JaredPar
@Marc, doh, forgot about that one.
JaredPar
i.e. class Foo : IMyInterface {} class Bar : Foo {}; Foo foo = new Bar(); MyMethod(foo); [variable is Foo, T is Foo, obj is Bar]; MyMethod<IMyInterface>(foo); [variable is Foo, T is IMyInterface, obj is Bar]
Marc Gravell
Just because I was curious, and so others might be as well, Jared was referring to this answers (apparently, leppie is also Joel): http://stackoverflow.com/questions/592584/what-is-lambda-lifting/593491#593491
Joel Coehoorn
@Joel, doh, like the answer said, I needed sleep :(
JaredPar
+4  A: 

Jared has mentioned some of the points; another interesting one: with generics, you can avoid boxing of value-types as long as you basically don't touch it... so I could have a struct Foo : IMyInterface and pass it in, and it won't get boxed.

The difference gets more noticeable with things like collections:

static void Foo(IEnumerable<IMyInterface> data) {}

vs

static void Foo<T>(IEnumerable<T> data) 
    where T : IMyInterface {}

Now, since C# 3.0 doesn't have covariance (except for arrays), I can't pass a List<Bar> to the top one, even if Bar : IMyInterface - but I can with the second (implicit T = Bar).

Marc Gravell
A: 

Another caveat to consider with this scenario is the fact that using "where T : <%your base interface or abstraction%>" can be overused in generics rendering your generic type non-generic in nature.

IE: Remember that by isolating your generic method to IMyInterface, you're isolating that method to only those types implementing IMyInterface. So if you've merely chosen to use IMyInterface based on good OOP principles, but you have only one (or in some cases a very small number of) potential type anywhere that'll be implementing that interface, then you've defeated the purpose of using generics. Under that circumstance, the first option would be better.

Only use "where" on your generic type when you're going to have a broader range of types that actually implement IMyInterface.

Boydski
+1  A: 

Another difference, using the generic method allows you to specify multiple interfaces that your object must implement:

class Dictionary<TKey,TVal>
    where TKey: IComparable, IEnumerable
    where TVal: IValue
{ ... }
Frank Krueger