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.