What would be a practical advantage of using generics vs interfaces in this case:
void MyMethod(IFoo f)
{
}
void MyMethod(T f) : where T : IFoo
{
2 years later I found a very simple and useful case. Consider this common pattern:
class MyClass : IDisposable {
public void Dispose() {
if (m_field1 != null) {
m_field1.Dispose();
m_field1 = null;
}
if (m_field2 != null) {
m_field2.Dispose();
m_field2 = null;
}
// etc
}
}
I've always wanted to write a helper method to avoid having to write all this boilerplate for every field:
class MyClass : IDisposable {
static void IfNotNullDispose(ref IDisposable disposable) {
if (disposable != null) {
disposable.Dispose();
disposable = null;
}
}
public void Dispose() {
IfNotNullDispose(ref m_field1);
IfNotNullDispose(ref m_field2);
// etc
}
}
Unfortunately this is illegal in C# because you cannot use an interface for ref parameters, you must use the concrete type you'll pass in and nothing else. So you'd have to write a different method for every single type of field you want to dispose. Oh wait that's exactly what generics do for you:
static void IfNotNullDispose<T>(ref T disposable) where T: class, IDisposable {
if (disposable != null) {
disposable.Dispose();
disposable = null;
}
}
Now everything works as intended!
In this particular case, there is no benefit. In general you wouldn't specify this at a method level, but at a class level. E.g.,
public interface IFoo {
void DoSomethingImportant();
}
public class MyContainer<T> where T : IFoo {
public void Add(T something){
something.DoSomethingImportant();
AddThisThing(something);
}
public T Get() {
T theThing = GetSomeKindOfThing();
return theThing;
}
}
Notice that we require T to implement IFoo because of the Add method where we need to call the DoSomethingImportantMethod implemented by IFoo.
But notice in the Get method that we will return the T provided by end user of this class instead of a plain old IFoo, which alleviates the need for the developer to always cast to their actual concrete T.
Example:
public class Bar : IFoo{
//....
}
MyContainer<Bar> m = new MyContainer<Bar>();
//stuff happens here
Bar b = m.Get();
Note that if I was just returning an IFoo, then I would have to do this at the last line instead:
Bar b = (Bar) m.Get();