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.