Search code examples
c#inheritancegeneric-method

generic types and inheritance confusion


I have a class hierarchy like the following:

public class Country : MainObj
public class MainObj : BaseEntity

and I have business logic classes like the following:

public class CountryBLL<TEntity> : CountryDLL<TEntity>,IBaseBLL<TEntity> where TEntity : Country
public class MainObjBLL<TEntity> : MainObjDLL<TEntity>, IBaseBLL<TEntity> where TEntity : MainObj

Now the thing I want to implement is a function in that I decide which class and bll should I get for this I added IBaseBLL interfaces for return type of my function

My function is the following:

    public static IBaseBLL<T> GetProperBllFromObjName<T>(string entityName)
    { 
        IBaseBLL<T> baseBLL = null;
        switch (entityName)
        { 
            case "Country":
                CountryBLL<Country> aa = new CountryBLL<Country>(); 
                baseBLL = (IBaseBLL<T>) aa; //error line
                break;
        }


        return baseBLL;
    }

when I call the function like this:

IBaseBLL<BaseEntity> mainBll = GetProperBllFromObjName("Country");

But I am unable to cast exception in line where i added comment "error line"

so what should i do in this case. The only thing i want is writing a function to decide which bll should i use. (i dont want to change bll declerations).


Solution

  • If you add out to the definition of IBaseBLL<T> like this: <out T> it will probably work (can't see the rest of your code to make sure there isn't something else), unless you have methods on IBaseBLL<T> that have T as an input parameter - that would certainly break it (as it won't even compile).

    The following works, but if you take out the out keyword you'll get the exception:

    namespace MyProgram
    {
        public class BaseEntity {}    
        public class CountryDLL<TEntity> {}    
        public class MainObjDLL<TEntity> {}    
        public interface IBaseBLL<out TEntity> {}    
        public class MainObj: BaseEntity {}    
        public class Country : MainObj {}    
        public class CountryBLL<TEntity> : CountryDLL<TEntity>,IBaseBLL<TEntity> where TEntity : Country {}    
        public class MainObjBLL<TEntity> : MainObjDLL<TEntity>, IBaseBLL<TEntity> where TEntity : MainObj {}    
    
        class Program
        {    
            public static IBaseBLL<T> GetProperBllFromObjName<T>(string entityName)
            { 
                IBaseBLL<T> baseBLL = null;
                switch (entityName)
                { 
                    case "Country":
                        CountryBLL<Country> aa = new CountryBLL<Country>(); 
                        baseBLL = (IBaseBLL<T>) aa; //error line
                        break;
                }
    
                return baseBLL;
            }
    
            static void Main()
            {
                IBaseBLL<Country> c = GetProperBllFromObjName<Country>("Country");
                IBaseBLL<BaseEntity> d = GetProperBllFromObjName<BaseEntity>("Country");
            }
        }
    }
    

    Using out and its partner, in, is called contravariance and covariance in C#.

    There's plenty of other material on it online. I'd suggest reading about it.

    One thing I haven't read that I know is how to remember the difference - it's pretty easy imho. If all your methods return T then you can add out (think of a collection and returning items in the collection - they come out of the collection). If all your methods accept T then you can add in (again, collection - you can add things and they go in the collection). However if you have methods that do both you cannot add either keyword to the generic type parameter. Also once you choose a keyword and code against it or release it you're suck; you can always add it later and be okay, but once you've chosen one you're stuck with it.