views:

1200

answers:

11

What are most important things you know about generics: hidden features, common mistakes, best and most useful practices, tips...

I am starting to implement most of my library/API using generics and would like to collect most common patterns, tips, etc., found in practice.

Let me formalize the question: What is the most important thing you've learned about generics?

Please try to provide examples -- it would be easier to understand, as opposed to convoluted and overly-dry descriptions

Thanks

This question is somewhat similar to Jon's question, though, on a different subject.

+11  A: 

One of the most important things I've learned is that you can constrain the generic type parameter(s). This can be very powerful, allowing you to take customize the class for only certain types of objects and allowing you to use the members of that type in your generic class. I realize that this is pretty fundamental, but it's one of the things that makes generics incredibly useful.

tvanfosson
+3  A: 

Understand the capabilities and limitations of generic type inference in C#. A deep understanding of what the compiler can, and can't, infer based on (e.g.) the types of parameters in your method can be leveraged to make the common use-cases of your API significantly more readable.

Greg D
please provide an example....I'd like to see it in action
Most of LINQ is an example, actually. :) Tons of generic APIs, but notice that you almost never have to actually specify a type when using it.
Greg D
+2  A: 

The most important lesson about generics I've learned is: the more you use them the better.

Pop Catalin
A: 

First of all it is inportant to know how Generics work in C#. This article gives you a good overview of generics by Anders Hejlsberg (The father of c#). I don't think that using them as often as possible is that good. Use generics when they really make sense. Always remember KISS and YAGNI (Keep It Simple Stupid; You Ain't Gonna Need It) from extreme programming.

crauscher
A: 

Generic delegate types are always type invariant.

I ran into an issue similar to what is outlined at the link below the other day, and it caused some confusion because I didn't understand why I had to cast my collection.

http://www.theserverside.net/blogs/thread.tss?thread_id=47323

Ian P
+3  A: 

Each specialization of a generic type is treated as a unique type when it comes to things like static members. For example, with this type:

class GenericType<T>
{
    public static int SomeValue;
}

The assert succeeds if we do this:

GenericType<int>.SomeValue = 3;
Debug.Assert(GenericType<double>.SomeValue == 0);

This is because:

typeof(GenericType<int>) != typeof(GenericType<double>)

Even though

typeof(GenericType<int>.GetGenericTypeDefinition() == typeof(GenericType<double>).GetGenericTypeDefinition()
Jeff Moser
+1  A: 

Don't know if they are most important, but I've learned the following:

Generics will only be instantiable via reflection if you don't know the frikkin type. In some cases you may need non-generic interfaces to use your generic classes in situations where the type is unknown.

I almost wrecked my head until I grocked that

public class Foo<T> where T : Foo<T> {
  public T CloneMe() ...
}

is perfectly valid code and allows your base class to expose methods and properties related to the specialized class...that ended up in a definition of a state machine along its states:

public abstract class Machine<S,M> where S : State<S,M> where M : Machine<S,M>  {
    protected S state;
}

public abstract class State<S,M> where S : State<S,M> where M : Machine<S,M> {
    protected M machine;
}

Generics can get a bit unwieldy. The other day I had this:

List<Tuple<Expression<Func<DataTable,object>>,Expression<Func<DataTable,object>>>>

phew...

flq
Good stuff -- keep it coming!
With regards to the last code snippet, I had something very similar a few months ago. I refactored it into something a litle more simple and readable though.
dotnetdev
@GSS - That's what I did as well. It's just not very readable. I derived from Tuple for this. Just now I refactored it again because it turns out that the class needs more semantics :) It's a funny life to be a developer, always movin'!
flq
+1  A: 
MyGeneric<T> where T : IComparable

doesn't make

MyGeneric<IComparable>

a base class of it.

Rauhotz
Good one, though I've learned it, originally, from C++
+1  A: 

I've learnt that generics is indeep powerful tool yet misused leads to very unreadable code.

Migol
+2  A: 

No covariance or contra-variance (at least in 3.5). Be aware of this when designing class hierarchies that include generic type parameters.

Jason Jackson
It's finally here, baby! Also note that the CLR already had some support for this (with + and - annotations in IL), but the languages and compilers did not provide syntax for it.
Martinho Fernandes
I was actually disappointed in the variance introduced. I think what is there is fine, but doesn't go far enough.
Jason Jackson
+2  A: 

Two interesting lessons. First; with lists; try to think in terms of T; for full details see here, but in short you need to use:

public void Foo<T>(IList<T> data) where T : SomeBaseClassOrInterface {}

and not:

public void Foo(IList<SomeBaseClassOrInterface> data) {}


Second: watch for the edge cases ;-p

Can you see the trap here?

static void Foo<T>() where T : new()
{
    T t = new T();
    Console.WriteLine(t.ToString()); // works fine
    Console.WriteLine(t.GetHashCode()); // works fine
    Console.WriteLine(t.Equals(t)); // works fine

    // so it looks like an object and smells like an object...

    // but this throws a NullReferenceException...
    Console.WriteLine(t.GetType()); // BOOM!!!
}
Marc Gravell
Mark, explain the Boom part? Is it due to the fact that T could be a value type -- and GetType is NOT available for it?
see the link 'watch for the edge cases'
johnc