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.

Leave a Reply

Close Bitnami banner
Bitnami