C# generic types are not C++ templates. A template lets you do a fancy "search and replace" where you would substitute the name of a type that implements a static parse method for T. C# generics are not a textual search-and-replace mechanism like that. Rather, they describe parameterized polymorphism on types. With a template, all that is required is that the specific arguments you substitute for the parameters are all good. With a generic every possible substitution whether you actually do it or not, has got to be good.
UPDATE:
A commenter asks:
What would be the C# way of doing things when an equivalent to Haskell's Read type class is needed?
Now we come to the deep question underlying the original question.
To clarify for the reader unfamiliar with Haskell: Since C# 2.0, C# has supported "generic" types, which are a "higher" kind of type than regular types. You can say List<int>
and a new type is made for you that follows the List<T>
pattern, but it is a list specifically of integers.
Haskell supports an even higher kind of type in its type system. With generic types you can say "every MyCollection<T>
has a method GetValue
that takes an int and returns a T
, for any T
you care to name". With generic types you can put constraints on T and say "and furthermore, T is guaranteed to implement IComparable<T>
..." With Haskell typeclasses you can go even further and say the moral equivalent of "...and moreover, T is guaranteed to have a static method Parse
that takes a string and returns a T".
The "Read" typeclass is specifically that typeclass that declares the moral equivalent of "a class C that obeys the Read typeclass pattern is one that has a method Parse that takes a string and returns a C".
C# does not support that kind of higher type. If it did then we could typecheck patterns in the language itself such as monads, which today can only be typechecked by baking them into the compiler (in the form of query comprehensions, for example.) (See Why there is no something like IMonad<T> in upcoming .NET 4.0 for some more thoughts.)
Since there is no way to represent that idea in the type system, you're pretty much stuck with not using generics to solve this problem. The type system simply doesn't support that level of genericity.
People sometimes do horrid things like:
static T Read<T>(string s)
{
if (typeof(T) == typeof(int)) return (T)(object)int.Parse(s);
if ...
but that is in my opinion a bit abusive; it really is not generic.