C# - generic methods vs. non-generic methods - c#

I'm a bit confused about why/when I'd ever want to use a generic method since a non-generic method can access the generic members of its containing class and be passed generic arguments anyway.
So, using a canned example that likely misses the point (yet highlights why I'm asking this question), why would I do this:
public class SomeGeneric<T>
{
public T Swap<T>(ref T a, ref T b)
{
T tmp = a;
a = b;
b = tmp;
}
}
over
public class SomeGeneric<T>
{
public T Swap(ref T a, ref T b)
{
T tmp = a;
a = b;
b = tmp;
}
}
this?
Or, really, why would I want to use a generic method at all?

You'd typically use a generic method in a type that isn't generic.
For example, look at the Enumerable class. It defines the generic extension methods for most of the LINQ fucntionaltiy, but itself isn't generic.
You also might want a generic method within a generic type, but only if the generic method used a different generic type specifier.
This lets you write something like the following:
class Foo<T> where T : IConvertible, IComparable<T>
{
int CompareTo<U>(U other) where U : IConvertible
{
// Convert to this
T otherConverted = Convert.ChangeType(other, typeof(T));
return this.CompareTo(otherConverted);
}
}
(Granted, this is a bit contrived, but does compile and work correctly for Foo<int> comparing to a double, etc)

What if the containing class is not generic? What if it has different generic type parameters?

The first example does not make much sense, because class parameter is not used. Consider another example though:
public class SomeGeneric<T>
{
public K ConvertTo<T>(T a)
{
return CodeThatConvertsTtoK(a);
}
}
and its usage:
new SomeGeneric<int>().ConvertToInt("ten");

A common scenario for method level type parameters are extension methods because they must be declared in a non-generic static class. But they are required for every generic member in a non-generic type.
public static class Extensions
{
public static void Foo<A, B>(this A a, B b) { [...] }
public static T Bar<T>(this String input) { [...] }
public static U FooBar<V, W>(this V v, W w) { [...] }
}

If both the class and the method are generic, the type parameters ("generic parameters") must have different names, of course. There can't be two different things named T like in your first example.
If your method is non-static (as it seems), if you choose to make the containing class generic, the type will have to be specified already when you instantiate your class. Like var obj = new SomeGeneric<DateTime>();. So it should be something that logically "belongs" to the object modelled by the class.
If your method is static, and you choose to make the class generic, you will still have to specify the type parameter together with the class somehow. If the method is called from outside the class, it would go like SomeGeneric<DateTime>.Swap(ref a, ref b);.
The advantage with making the method generic, is that in many cases you can use type inference which allows you to omit the angle bracketed type parameter. You can only do this with generic methods. Example: nonGeneric.Swap(ref a, ref b); where the Swap<T> method is generic. The compiler will look at the compile-time types of a and b and figure out which T fits in, without you specifying it.
Conclusion: If the T does not logically belong to the class (as in List<T>), put it with the method.

Here's one example where generic methods really shine. Consider an expression such as 1+2 expressed as a binary tree. You want to implement the Visitor pattern on the entire tree, with the goal being some sort of map/reduce operations. Some examples would be:
Reducing an expression to a string to print it
Reducing an expression to a double to calculate its value
Mapping an expression to another expression with some members altered/added/removed
All of these operations can be put behind a Visitor pattern method:
public abstract class Expression
{
public abstract T Reduce<T>(ITransformer<T> transformer);
}
This is similar to the classic Visitor implementation, but the terminology is changed: we have Reduce() instead of Accept() and an ITransformer<T> instead of an IVisitor. Notice that the method is generic.
This approach allows us to create any number of ITransformer<T> classes that transform the hierarchy to any type T, supporting map-reduce operations.

Related

Difference between C# interface and Haskell Type Class

I know that there is a similar question here, but I would like to see an example, which clearly shows, what you can not do with interface and can with Type Class
For comparison I'll give you an example code:
class Eq a where
(==) :: a -> a -> Bool
instance Eq Integer where
x == y = x `integerEq` y
C# code:
interface Eq<T> { bool Equal(T elem); }
public class Integer : Eq<int>
{
public bool Equal(int elem)
{
return _elem == elem;
}
}
Correct my example, if not correctly understood
Typeclasses are resolved based on a type, while interface dispatch happens against an explicit receiver object. Type class arguments are implicitly provided to a function while objects in C# are provided explicitly. As an example, you could write the following Haskell function which uses the Read class:
readLine :: Read a => IO a
readLine = fmap read getLine
which you can then use as:
readLine :: IO Int
readLine :: IO Bool
and have the appropriate read instance provided by the compiler.
You could try to emulate the Read class in C# with an interface e.g.
public interface Read<T>
{
T Read(string s);
}
but then the implementation of ReadLine would need a parameter for the Read<T> 'instance' you want:
public static T ReadLine<T>(Read<T> r)
{
return r.Read(Console.ReadLine());
}
The Eq typeclass requires both arguments have the same type, whereas your Eq interface does not since the first argument is implicitly the type of the receiver. You could for example have:
public class String : Eq<int>
{
public bool Equal(int e) { return false; }
}
which you cannot represent using Eq. Interfaces hide the type of the receiver and hence the type of one of the arguments, which can cause problems. Imagine you have a typeclass and interface for an immutable heap datastructure:
class Heap h where
merge :: Ord a => h a -> h a -> h a
public interface Heap<T>
{
Heap<T> Merge(Heap<T> other);
}
Merging two binary heaps can be done in O(n) while merging two binomial heaps is possible in O(n log n) and for fibonacci heaps it's O(1). Implementors of the Heap interface do not know the real type of the other heap so is forced to either use a sub-optimal algorithm or use dynamic type checks to discover it. In contrast, types implementing the Heap typeclass do know the representation.
A C# interface defines a set of methods that must be implemented. A Haskell type class defines a set of methods that must be implemented (and possibly a set of default implementations for some of the methods). So there's a lot of similarities there.
(I guess an important difference is that in C#, an interface is a type, whereas Haskell regards types and type classes as strictly separate things.)
The key difference is that in C#, when you define a type (i.e., write a class), you define exactly what interfaces it implements, and this is frozen for all time. In Haskell, you can add new interfaces to an existing type at any time.
For example, if I write a new SerializeToXml interface in C#, I cannot then make double or String implement that interface. But in Haskell, I can define my new SerializeToXml type class, and then make all the standard, built-in types implement that interface (Bool, Double, Int...)
The other thing is how polymorphism works in Haskell. In an OO language, you dispatch on the type of the method the object is being invoked on. In Haskell, the type that the method is implemented for can appear anywhere in the type signature. Most particularly, read dispatches on the return type you want — something you usually can't do at all in OO languages, not even with function overloading.
Also, in C# it's kind of hard to say "these two arguments must have the same type". Then again, OO is predicated on the Liskov substitution principal; two classes that both descend from Customer should be interchangeable, so why would you want to constrain two Customer objects to both be the same type of customer?
Come to think of it, OO languages do method lookup at run-time, whereas Haskell does method lookup at compile-time. This isn't immediately obvious, but Haskell polymorphism actually works more like C++ templates than usual OO polymorphism. (But that's not especially to do with type classes, it's just how Haskell does polymorphism as such.)
Others have already provided excellent answers.
I only want to add a practical example about their differences. Suppose we want to model a "vector space" typeclass/interface, which contains the common operations of 2D, 3D, etc. vectors.
In Haskell:
class Vector a where
scale :: a -> Double -> a
add :: a -> a -> a
data Vec2D = V2 Double Double
instance Vector (Vec2D) where
scale s (V2 x y) = V2 (s*x) (s*y)
add (V2 x1 y1) (V2 x2 y2) = V2 (x1+x2) (y2+y2)
-- the same for Vec3D
In C#, we might try the following wrong approach (I hope I get the syntax right)
interface IVector {
IVector scale(double s);
IVector add(IVector v);
}
class Vec2D : IVector {
double x,y;
// constructor omitted
IVector scale(double s) {
return new Vec2D(s*x, s*y);
}
IVector add(IVector v) {
return new Vec2D(x+v.x, y+v.y);
}
}
We have two issues here.
First, scale returns only an IVector, a supertype of the actual Vec2D. This is bad, because scaling does not preserve the type information.
Second, add is ill-typed! We can't use v.x since v is an arbitrary IVector which might not have the x field.
Indeed, the interface itself is wrong: the add method promises that any vector must be summable with any other vector, so we must be able to sum 2D and 3D vectors, which is nonsense.
The usual solution is to switch to F-bounded quantification AKA CRTP or whatever it's being called these days:
interface IVector<T> {
T scale(double s);
T add(T v);
}
class Vec2D : IVector<Vec2D> {
double x,y;
// constructor omitted
Vec2D scale(double s) {
return new Vec2D(s*x, s*y);
}
Vec2D add(Vec2D v) {
return new Vec2D(x+v.x, y+v.y);
}
}
The first time a programmer meets this, they are usually puzzled by the seemingly "recursive" line Vec2D : IVector<Vec2D>. I surely was :) Then we get used to this and accept it as an idiomatic solution.
Type classes arguably have a nicer solution here.
After a long study of this issue, I came to an easy method of explaining. At least for me it's clear.
Imagine we have method with signature like this
public static T[] Sort(T[] array, IComparator<T> comparator)
{
...
}
And implementation of IComparator:
public class IntegerComparator : IComparator<int> { }
Then we can write code like this:
var sortedIntegers = Sort(integers, new IntegerComparator());
We can improve this code, first we create Dictionary<Type, IComparator> and fill it:
var comparators = new Dictionary<Type, IComparator>()
{
[typeof(int)] = new IntegerComparator(),
[typeof(string)] = new StringComparator()
}
Redesigned IComparator interface so that we could write like above
public interface IComparator {}
public interface IComparator<T> : IComparator {}
And after this let's redesign Sort method signature
public class SortController
{
public T[] Sort(T[] array, [Injectable]IComparator<T> comparator = null)
{
...
}
}
As you understand we are going to inject IComparator<T>, and write code like this:
new SortController().Sort<int>(integers, (IComparator<int>)_somparators[typeof(int)])
As you already guessed this code will not work for other types until we outline the implementation and add in Dictionary<Type, IComparator>
Notice, the exception we will see only on runtime
And now imagine if this work was done for us by the compiler during build and it threw exception if it could not find the comparator with corresponding types.
For this, we could help the compiler and add a new keyword instead of usage attribute. Out Sort method will be look like this:
public static T[] Sort(T[] array, implicit IComparator<T> comparator)
{
...
}
And code of realization concrete Comparator:
public class IntegerComparator : IComparator<int> implicit { }
Note, we use the keyword 'implicit', after this compiler will be able to do
routine work, which we wrote above, and the exception will be thrown during
compile-time
var sortedIntegers = Sort(integers);
// this gives us compile-time error
// because we don't have implementation of IComparator<string>
var sortedStrings = Sort(strings);
And give the name to this style of implementation Type Class
public class IntegerComparator : IComparator<int> implicit { }
I hope that I understood correctly and understandably explained.
PS: The code does not pretend to work.

How to define generic extension method that returns type of sub generic

I have a definition like this:
public static IQueryable<D> ReturnDTO<E, D>(this IQueryable<E> query)
where D : BaseDTO, new()
where E : BaseObjectWithDTO<D, int>
{
//expression tree code to convert
}
BaseObjectWithDTO defines what type it's DTOs are. Hence I would have thought the by defining E I would have been also defining D.
But IQueryable.ReturnDTO() requires that the generic parameters be specified like this:
IQueryable.ReturnDTO<someEntity, someDTO>();
Which is obviously UGLY.
I tried making this IQueryable<E> as this IQueryable<BaseObjectWithDTO<D, int>> instead but then this has nothing as the in of the func because it won't take a type inferred by the Generic Parameter of the IQuerayble:
var projection = Expression.Lambda<Func<E, D>>(memberInitExpression, itemParam);
Ideas on how to get this to not require the types be passed every time?
Unfortunately, C#'s generic type inference system isn't as powerful as it could be. If you include a parameter involving D, then it can infer it. For example...
public static IQueryable<D> ReturnDTO<E, D>(this IQueryable<E> query,
IQueryable<BaseObjectWithDTO<D, int>> dummy)
// now you can do...
myQueryable.ReturnDTO(myQueryable);
// instead of
myQueryable.ReturnDTO<BaseObjectWithDTO<BaseDTO, int>, BaseDTO>();
It's confusing and arguably a poor design to pass the same variable in twice, but it's better (IMHO) than having to explicitly specify the types or resort to reflection or other runtime techniques to extract the types (when that's otherwise unnecessary).
Since you aren't actually going to use the dummy parameter, it doesn't matter what the value is, as long as the type is right, so you might still be able to use this at the end of a query chain, e.g. this will still return the expected value, even though you pass in two different IQueryables.
var result = otherQueryable.Where(...).ReturnDTO(otherQueryable);
If you prefer to be slightly less cryptic, you could make the dummy parameter D dummy, and then e.g. myQueryable.ReturnDTO(default(SomeDTO)) (here using default as a clear way of getting a null or default value without having a reference to a variable/field/property of that type) if you prefer.
I don't think it is possible as you currently have it designed, this MSDN page states that type inference is not possible in this scenario:
The same rules for type inference apply to static methods and instance
methods. The compiler can infer the type parameters based on the
method arguments you pass in; it cannot infer the type parameters only
from a constraint or return value.
That means you have to pass in a parameter of your type to this method for the compiler to be able to infer the types.
You have to specify the type, but it doesn't have to be done explicitly in the q.Return<E,D>(). There are ways that you can pass specify the type parameter so that it can be inferred implicitly. To do that, you'll need to change the signature a bit.
public static IQueryable<D> ReturnDTO<E, D>(this IQueryable<E> query, D dtoTypeExample = default(D))
where D : BaseDTO, new()
where E : BaseObjectWithDTO<D, int>
{
//expression tree code to convert
}
Now, even though there's a default parameter, the compiler won't be able to get it unless you pass some argument in. The thing you pass in doesn't have to be used by the method in any other way though. For example, assume you have:
public class ProductDTO : BaseDTO {
public static ProductDTO Empty { get { return new ProductDTO(); } }
}
public class Product : BaseObjectWithDTO<ProductDTO,int> {
public static IQueryable<Product> QuerySource { get; set; }
}
You could then call:
ProductDTO dto = Product.QuerySource.ReturnDTO(ProductDTO.Empty);
I'm not saying that this is necessarily a good idea, but you could do it. Also, it doesn't have to be the actual type that you pass in - you just need to pass in something that's close enough for the compiler to infer the intended type. For example, you could have a signature like:
public static IQueryable<D> ReturnDTO<E, D>(this IQueryable<E> query, Func<D,D> dtoIdentity = default(Func<D,D>))
where D : BaseDTO, new()
where E : BaseObjectWithDTO<D, int>
{
//expression tree code to convert
}
then if you have:
public class ProductDTO : BaseDTO {
public static ProductDTO Identity(ProductDTO dto){ return dto; };
}
public class Product : BaseObjectWithDTO<ProductDTO,int> {
public static IQueryable<Product> QuerySource { get; set; }
}
You could then call:
ProductDTO dto = Product.QuerySource.ReturnDTO(ProductDTO.Identity);
This might make more semantic sense to some, but it's somewhat subjective. Once again, I'm not recommending this, just saying that you can do it. If you do decide to do it though, it might save you a little work to have a self-referential generic base (Warning: Eric Lippert discourages this kind of thing). But anyway, your design would then look like:
public abstract class BaseDTO<T> where T : BaseDTO<T>, new()
{
public static T Empty { get { return new T(); } }
}
public class ProductDTO : BaseDTO<ProductDTO> { }
You could also add the type constraint to your ReturnDTO method if you want to enforce an invariant that all DTOs were then self-referential derivatives of BaseDTO<T> with public parameterless constructors. But, if you're trying to write what would conventionally be considered good code you probably won't do any of this and you'll just close your eyes and explicitly use the parameter constraint if you think it's ugly.
There is one other thing I thought of, which wouldn't be so frowned upon. Think about the Queryable.Cast<T> and Queryable.OfType<T> methods. They take a non generic IQueryable parameter but returns an IQueryable<T>. If you make sure to validate your assumptions about the parameter, it's probably clean enough. Then you would lose some compile-time type-safety though. You would need to have a non-generic base like BaseObjectWithDTO that BaseObjectWithDTO<TData,TKey> would inherit from. Your method would then look like:
public static IQueryable<D> ReturnDTO<D>(this IQueryable<BaseObjectWithDTO> query)
where D : BaseDTO, new()
{
if(query == null) throw new ArgumentNullException("query");
if( !typeof(BaseObjectWithDTO<D,int>) .IsAssignableFrom(query.GetType().GetGenericParameters()[0]))
throw new ArgumentOutOfRangeException("query");
//expression tree code to convert
}
That's not terrible. But it might not be good either. It's probably better than the other options I listed, but who knows.
Another syntax that might work for you just occurred to me, but it's also pretty abusive. Imagine you did go the BaseDTO<T> where T : BaseDTO<T>,new() route. You could declare the method on that type to extract the DTO queryable. This is what I'm thinking:
public abstract class BaseDTO<T>
where T : BaseDTO<T>, new()
{
public static T From(BaseObjectWithDTO<T,int> entity){
if(entity == null) throw new ArgumentNullException("entity");
//expression tree code to convert
}
}
then you don't really need that method ReturnDTO as an extension method anymore, because you have normal LINQ. You could still add it as syntactic sugar if you want, but using these semantics instead, your call ends up looking like:
IQueryable<ProductDTO> dtoQuery = from entity in Product.QuerySource select ProductDTO.From(entity);
which can also be written as
Product.QuerySource.Select(entity => ProductDTO.From(entity));
and if you were using an IEnumerable instead of an IQueryable could be
Product.QuerySource.Select(ProductDTO.From);
Please remember: All I'm saying is that you can do things this way. I'm not saying you should.

Is there an (elegant) solution to constrain a generic type argument further within a method?

I have a generic base class Foo<T> from which the classes Bar<U> and Bat<T> derive.
U derives from T. Bat and Bar are similar implementations that differ only in a few places where values of type U must be handled in a different manner.
In Foo, I have a factory method Create that takes an argument of type T and should create either a Bar or Bat object.
It looks roughly like this:
public static IFoo<T> Create(T input) {
if (input.TypeIdentifier == Types.Bar) {// exemplary type check
// input is of or derives from `U`
// return a Bar<U>
} else
return new Bat(input);
}
// usage:
U myU = new ClassThatDerivesFromU();
T myT = new ClassThatDerivesFromT(CouldBe.Of(Type.U));
var myFoo1 = Create(myU); // of type IFoo<U>
var myFoo2 = Create(myT); // of type IFoo<T>
Since T is not a U, I cannot instantiate a Bar object.
One possible solution would be this:
public static U To<T, U>(T input) where U : T {
return input as U;
}
// to create Bar:
new Bar(To<T, U>(input));
However this is quite the hack imo and would not be usable with structs (U in this case cannot be a struct anyway due to inheritance, but I have another case where I want to call methods depending on if T is a struct or a class for example).
In C++ a scenario like this can be solved (iirc) by providing several overloads of the Create method with different type constraints and the compiler will check the type T and pick the right method (with either U or T as type constraint).
I'm not aware of a similar built-in solution in C#, but perhaps there is an elegant workaround I can use instead? (Reflection is an obvious answer, but not an option)
Yes, generic variance is allowed when using interfaces. You can declare the generic type parameter within IFoo to be either covariant or contravariant (depending upon the usage). If you wish to use a more derived type, then the type T must be contravariant and IFoo can be declared as follows:
interface IFoo<in T> { ... }
Have a look at this MSDN page for more information on generics and variance in C#.
Update
Once you have the condition that an IFoo<U> is IFoo<T> if U : T (eg the generic type of IFoo is contravariant) then you are free to safely cast within your create method:
return (IFoo<T>)((object)new Bar<U>());

Method overloading in generic class

I am working with a code that contains following overloaded method in generic class:
public class A<T>
{
public void Process(T item) { /*impl*/ }
public void Process(string item) { /*impl*/ }
}
When parametrizing the class for string do I lose the possibility to call the version with generic parameter?
var a = new A<string>();
a.Process(""); //Always calls the non-generic Process(string)
Specific types take precedence over generic types.
For example, this is what I tested with in LINQPad.
void Main()
{
new A<string>().Process("Hello");
}
public class A<T>
{
public void Process(T item) { Console.WriteLine("T"); }
public void Process(string item) { Console.WriteLine("string"); }
}
// Output: string
If you have a problem with hiding the generic method, then you need to rethink something. By overloading a generic method with specific types, you are effectively saying, "Use the generic overload if you need to, but if you can, use the specific version, because it should know what is best."
There is one way I just discovered, but it's a bit cross-eyed. Because generics and overloading get resolved in build time, you can define a generic method:
public static CallerClass
{
public static CallGenericOverload<T>(GenericClass<T> cls, T val)
{
return cls.ProblemOverload(val);
}
//We can also make an extension method.
//We don't have to of course, it's just more comfortable this way.
public static CallGenericOverloadExtension<T>(this GenericClass<T> cls, T val)
{
return cls.ProblemOverload(val);
}
}
public GenericClass<T>
{
public string ProblemOverload(T val)
{
return "ProblemOverload(T val)";
}
public string ProblemOverload(string val)
{
return "ProblemOverload(string val)";
}
}
Now, if we do the following:
var genClass = new GenericClass<string>();
Console.WriteLine(genClass.ProblemOverload("")); //output: ProblemOverload(string val)
Console.WriteLine(CallerClass.CallGenericOverload(genClass, "")); //output: ProblemOverload(T val)
Console.WriteLine(genClass.CallGenericOverloadExtension("")); //output: ProblemOverload(T val)
You can use a similar trick if you define a generic class instead of a generic method. The important thing is that the parameter you transfer to ProblemOverload needs to be of type T rather than type string in the invocation. After all, the method CallGenericOverload knows it's getting a T at build time, so it's going to bind to the overload that accepts the parameter. It doesn't matter that it's actually going to get a string at runtime.
Yes. This is documented in the C# spec, section 7.5.3, overload resolution.
From 7.5.3.6:
"While signatures as declared must be unique, it is possible that substitution of type arguments results in identical signatures. In
such cases, the tie-breaking rules of overload resolution above will
pick the most specific member."
The example given in there states that in the case below, overload resolution for G<int>.F1 will pick non-generic
class G1<U>
{
int F1(U u);
int F1(int i);
}
The tie-breaking rule that applies here is outlined in 7.5.3.2, "Better function member":
In case the parameter type sequences {P1, P2, …, PN} and {Q1, Q2, …,
QN} are equivalent (i.e. each Pi has an identity conversion to the
corresponding Qi), the following tie-breaking rules are applied, in
order, to determine the better function member.
If MP is a non-generic method and MQ is a generic method, then MP is better than MQ.
Having done this before, I'm inclined to say "No," but there's always more knowledgable folks who would argue otherwise.
If memory serves, the runtime compiler chooses the most strongly typed overload to execute.
CLARIFICATION
My answer is badly worded, and I deserve the downvote.
The OP asked, "When parametrizing the class for string do I lose the possibility to call the version with generic parameter?" I wasn't answering that "No, you can't do that," but that "No, you don't lose the ability to call the version with the generic parameter."
I should have been more clear.

What are the advantages of using generics in method signatures?

(Thanks everyone for the answers, here is my refactored example, in turn another StackOverflow question about the Single Responsibility Principle.)
Coming from PHP to C#, this syntax was intimidating:
container.RegisterType<Customer>("customer1");
until I realized it expresses the same thing as:
container.RegisterType(typeof(Customer), "customer1");
as I demonstrate in the code below.
So is there some reason why generics is used here (e.g. throughout Unity and most C# IoC containers) other than it just being a cleaner syntax, i.e. you don't need the typeof() when sending the type?
using System;
namespace TestGenericParameter
{
class Program
{
static void Main(string[] args)
{
Container container = new Container();
container.RegisterType<Customer>("test");
container.RegisterType(typeof(Customer), "test");
Console.ReadLine();
}
}
public class Container
{
public void RegisterType<T>(string dummy)
{
Console.WriteLine("Type={0}, dummy={1}, name of class={2}", typeof(T), dummy, typeof(T).Name);
}
public void RegisterType(Type T, string dummy)
{
Console.WriteLine("Type={0}, dummy={1}, name of class={2}", T, dummy, T.Name);
}
}
public class Customer {}
}
//OUTPUT:
//Type=TestGenericParameter.Customer, dummy=test, name of class=Customer
//Type=TestGenericParameter.Customer, dummy=test, name of class=Customer
One reason when generics are very useful is when the generic type parameter is used as the type of a parameter or as the return type of the method.
That means, you can write methods like
public T GetAs<T>(string name)
where the return type can be checked by the compiler and boxing value types can sometimes be avoided.
The caller would write:
int value = GetAs<int>("foo");
Whithout generics, you would have to write
public object GetAs(Type t, string name)
and the caller has to cast the result again:
int value = (int)GetAs(typeof(int), "foo");
A primary reason is the type safety at compile time. If you are passing two Type objects you are placing the responsibility at the developer instead of the compiler.
This is also why many IoC containers utilizes it, as your compiler will complain if an concrete type isn't inheriting the abstract type.
public void Register<TAbstract, TConcrete>() where TConcrete : TAbstract
{
}
This code will only work if TConcrete is implementing or inheriting TAbstract. If this method took two Type parameters, your method should validate this relationship.
A simple answer is type inference where possible.
If the generic type is used in the method signature, you can omit it because the type could be inferred:
void SomeMethod<T>(T x, T y) where T : IComparable<T> {
Console.WriteLine("Result: {0} to {1} is {2}", x, y, x.CompareTo(y));
}
So the usage is simplified:
SomeMethod(3, 4); // instead of SomeMethod<int>(3, 4);
SomeMethod("one", "two"); // instead of SomeMethod<string>("one", "two");
If the generic type parameter is not used in the method signature the type inference is not possible:
var emptySequence = Enumerable.Empty<int>();
I think one of the primary uses is type safety with arguments and return values. In your example case, there is not much use for generics, because the input/output types (string) do not match the generic case (customers).
A more appropriate use might be:
public T RegisterType<T>(string name)
{
T obj = new T();
obj.DoSomething();
return obj;
}
or maybe
public void DoSomething<T>(T obj)
{
//operate on obj
}
If you didn't use Generics, you'd either have to overload a method for each type you want to support, or you'd have to accept the parameter as an object and perform casting logic.
For one example, compare the code needed to create an instance of your type using the typeof option versus a generic. Or return an instance of the type. Or accept an instance of the type as an argument. Or set a property on an instance of the type.
In general, if you will be working only with the type itself you can accept a type parameter. If you want to do anything with an instance of the type, use a generic.
Another reason to use a generic is if you want to apply constraints to the type. For example, you can require the type to implement one or several interfaces, inherit another type, be a reference type or value type, have a default constructor, or some combination of the above. The compiler will enforce this so you can't build code that doesn't comply with your requirements.
I'd say the best reason is type safety, using the "where" keyword, to ensure that the generic type is of a certain type (or sub-class/implementor). Using "typeof" will let you send anything through.

Categories

Resources