Some tips on C# Generics

Defining interfaces

You can define that a generic must implement an interface, which in essence allows you to know beforehand that a generic type will have a certain method (making it less generic)

public interface ISearchable
{
void Search();
}

public class SomeClass<T> where T : ISearchable
{
public void DoSomething(T entity)
{
entity.Search(); // Can do this on a generic type because it's implementing ISearchable
}
}

You can also use generics on the interfaces, in this case:

public interface ISearchable<TEntity>
{
TEntity Search();
}

public class SomeClass<T> where T : ISearchable<T>
{
public T FindMe(T entity)
{
return entity.Search();
}
}

Now when referencing the interface we must set the generic type too.

Warning!: If you set a constraint on a generic type any type given to the class will necessarily have to implement such type or it won’t compile, this is important to remember as when you didn’t define a generic type the compiler may be telling you that your type doesn’t follow the constraints on the generic type you are trying to emulate. So following the previous example:

public interface ISearchable<TEntity>
{
TEntity Search();
}

public class SomeClass<T> where T : ISearchable<T>
{
public T FindMe(T entity)
{
return entity.Search();
}
}

public class Dog : ISearchable<Dog>
{
public Dog Search()
{
throw new NotImplementedException();
}
}

public class Cat {}

public class AnotherClass
{
public AnotherClass()
{
var dog = new SomeClass<Dog>(); // Correct.
var cat = new SomeClass<Cat>(); // This won't compile
}
}

Generic methods

You can also use generics on methods:

public interface IMappeable
{
T MapAs<T>();
}

Now we can attach this method to any class allowing to define the type to which we map later.

public class CatAge : IMappeable
{
private int Age;

public T MapAs<T>()
{
var converter = TypeDescriptor.GetConverter(typeof(T));
var result = converter.ConvertTo(Age, typeof(T));
return (T)result;
}
}

public class AnotherClass
{
public AnotherClass()
{
var catAge = new CatAge();
var ageAsLong = catAge.MapAs<long>();
}
}

An interesting library to use here is System.ComponentModel.TypeConverter which allows us to convert from base types without knowing the type until run time.