none
Inheritance with generics RRS feed

  • Question

  • using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Linq.Expressions;

    namespace ConsoleApplication1
    {
        interface ISample<T>
        {
            T GetObject();
            IEnumerable<T> Where(Expression<Func<T, bool>> func);
        }

        public class Sample<P> : ISample<P> where P : new()
        {
            public P GetObject()
            {
                return new P();
            }
            public IEnumerable<P> Where(Expression<Func<P, bool>> func)
            {
                throw new NotImplementedException();
            }
        }

        public class Entity
        {
            public int ID { get; set; }
        }

        public class Person : Entity
        {
            public string PersonName { get; set; }
        }

        public class Employee : Entity
        {
            public string EmployeeName { get; set; }
        }


        class Program
        {
            static void Main(string[] args)
            {
                ISample<Entity> personObject = new Sample<Person>();
                ISample<Entity> empObject = new Sample<Employee>();
            }
        }
    }
    Monday, July 30, 2012 4:50 AM

Answers

  • Hi,

    For defining covariant generic parameters you can use the 'out' keyword like

     interface ISample<out T>

    But your method IEnumerable<T> Where(Expression<Func<T, bool>> func); won't work as Expression needs a contravariant+ covariant parameter. To use a covariant generic parameter the following rules must be satisfied.

    a) The type is used only as a return type of interface methods and not used as a type of method arguments. This is illustrated in the following example, in which the type R is declared covariant.

    b) The type is not used as a generic constraint for the interface methods. This is illustrated in the following code.

    So in your case you may need to use two generic parameters as shown below.

        interface ISample<out T,P> 
        {
            T GetObject();
            IEnumerable<T> Where(Expression<Func<P, bool>> func);
        }
        public class Sample<T,P> : ISample<T,P> where T : new() 
        {
            public T GetObject()
            {
                return new T();
            }
            public IEnumerable<T> Where(Expression<Func<P, bool>> func)
            {
                throw new NotImplementedException();
            }
        }
        public class Entity
        {
            public int ID { get; set; }
        }
        public class Person : Entity
        {
            public string PersonName { get; set; }
        }
        public class Employee : Entity
        {
            public string EmployeeName { get; set; }
        }
        class Program
        {
            static void Main(string[] args)
            {
                ISample<Entity,Entity> personObject = new Sample<Person,Entity>();
                Person p = (Person)personObject.GetObject();
            }
        }

    Good Luck!

    • Marked as answer by HimGarg Tuesday, July 31, 2012 8:48 AM
    Monday, July 30, 2012 12:10 PM

All replies

  • Now, whats your question here ?
    Monday, July 30, 2012 5:13 AM
  •  ISample<Entity> personObject = new Sample<Person>();
                ISample<Entity> empObject = new Sample<Employee>();

    Above two lines give compilation error

    Monday, July 30, 2012 9:34 AM
  • Hi,

    For defining covariant generic parameters you can use the 'out' keyword like

     interface ISample<out T>

    But your method IEnumerable<T> Where(Expression<Func<T, bool>> func); won't work as Expression needs a contravariant+ covariant parameter. To use a covariant generic parameter the following rules must be satisfied.

    a) The type is used only as a return type of interface methods and not used as a type of method arguments. This is illustrated in the following example, in which the type R is declared covariant.

    b) The type is not used as a generic constraint for the interface methods. This is illustrated in the following code.

    So in your case you may need to use two generic parameters as shown below.

        interface ISample<out T,P> 
        {
            T GetObject();
            IEnumerable<T> Where(Expression<Func<P, bool>> func);
        }
        public class Sample<T,P> : ISample<T,P> where T : new() 
        {
            public T GetObject()
            {
                return new T();
            }
            public IEnumerable<T> Where(Expression<Func<P, bool>> func)
            {
                throw new NotImplementedException();
            }
        }
        public class Entity
        {
            public int ID { get; set; }
        }
        public class Person : Entity
        {
            public string PersonName { get; set; }
        }
        public class Employee : Entity
        {
            public string EmployeeName { get; set; }
        }
        class Program
        {
            static void Main(string[] args)
            {
                ISample<Entity,Entity> personObject = new Sample<Person,Entity>();
                Person p = (Person)personObject.GetObject();
            }
        }

    Good Luck!

    • Marked as answer by HimGarg Tuesday, July 31, 2012 8:48 AM
    Monday, July 30, 2012 12:10 PM
  • Hi 

    If you are interested in the way Lists with IEnumberable interface which works covariantly, here is an example. ICovariant is a covariant interface. It has the  extension method Where.

        class Program
        {
            static void Main(string[] args)
            {
                SampleList<Person> persons = new SampleList<Person>();
                persons.Add(new Person { ID = 1 });
                persons.Add(new Person { ID = 2 });
    
    
                ICovariant<Entity> sample = persons;
                IEnumerable<Entity> selectdPersons=sample.Where(x => x.ID == 1);
    
                Person p = (Person)selectdPersons.ElementAt(0);
    
            }
        }
    
        public interface ICovariant<out T>
        {
            T[] GetObjects();
        }
    
        public interface ISampleList<T>
        {
            void Add(T t);
        }
    
        public class SampleList<T>:ICovariant<T>,ISampleList<T> where T : new()
        {
    
            T[] objects = new T[0];
            public void Add(T t)
            {
    
                Array.Resize<T>(ref objects, objects.Length + 1);
                objects[objects.Length - 1] = t;
    
            }
    
            public T[] GetObjects()
            {
                return objects;
            }
        }
    
        public static class SampleExtensions
        {
            public static IEnumerable<T> Where<T>(this ICovariant<T> test, Func<T, bool> predicate) where T : new()
            {
                IList<T> results = new List<T>();
                T[] objects = test.GetObjects();
                foreach (T t in objects)
                {
                    if ((bool)predicate.DynamicInvoke(t))
                    {
                        results.Add(t);
                    }
                }
                return results;
            }
    
        }
    
        public class Entity
        {
            public int ID { get; set; }
        }
    
        public class Person:Entity
        {
    
        }

    Good Luck!

    Monday, July 30, 2012 7:23 PM