Why does the following doesn't compile? (involves generics and inheritance in c#)

前端 未结 5 1707
野趣味
野趣味 2020-12-21 06:31

This compiles:

    class ReplicatedBaseType
    {
    }

    class NewType: ReplicatedBaseType
    {
    }

    class Document
    {
    ReplicatedBas         


        
相关标签:
5条回答
  • 2020-12-21 07:16

    This code compiles in VS2010, net framework 4

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace ConsoleApplication2
    {
        class ReplicatedBaseType
        {
        }
    
        class NewType : ReplicatedBaseType
        {
        }
    
        class Document
        {
            ReplicatedBaseType BaseObject;
    
            Document()
            {
                BaseObject = new NewType();
            }
        }
        interface DalBase<out T>  where T: ReplicatedBaseType
        {
        }
    
        class DalBaseExample<T> : DalBase<T> where T: ReplicatedBaseType
        {
    
        }
        class DocumentTemplate
        {
            DalBase<ReplicatedBaseType> BaseType;
            DocumentTemplate ()
            {
                BaseType = new DalBaseExample<NewType>(); // no error here
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-21 07:20

    the feature that you want is called "covariance" and was introduced only in C# 4.0 http://blog.t-l-k.com/dot-net/2009/c-sharp-4-covariance-and-contravariance

    you code fails because there is no such cast (both explicit and implicit). Current rules of C# (<= 3.0) forbid it.

    to check possible casts see §6.1.6 C# Specification

    0 讨论(0)
  • 2020-12-21 07:21

    As Andrey says, you want (generic) covariance. However:

    • Generic variance is only supported in C# 4
    • Generic variance isn't supported on classes
    • In your real life case, this may be unsafe.

    To go into the final point, suppose DalBase<T> has this method:

    void AddEntity(T entity)
    

    Now you've got something like this which you want to be able to compile - but would obviously be dangerous:

    DalBase<Fruit> fruitDal = new DalBase<Banana>();
    fruitDal.AddEntity(new Apple());
    

    The second line would have to compile - so for this to fail at compile time, it has to be the first line which would fail.

    I gave an hour long talk on generic variance recently which you may find useful if you want to know more - see the NDC 2010 video page and search for "variance". Alternatively you could read Eric Lippert's blog posts on the topic - but be aware that that will probably take longer than an hour ;)

    0 讨论(0)
  • 2020-12-21 07:31

    Variance exists in C# 4.0 targetting .NET 4), but is limited to interfaces and usage of in/out (oh, and arrays of reference-types). For example, to make a covariant sequence:

    class DalBase<T> : IEnumerable<T> where T: ReplicatedBaseType
    {
        public IEnumerator<T> GetEnumerator() {throw new NotImplementedException();}
        IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); }
    }
    
    class DocumentTemplate
    {
        IEnumerable<ReplicatedBaseType> BaseCollection;
        DocumentTemplate()
        {
            BaseCollection = new DalBase<NewType>(); // Error in this line. It seems this is not possible
        }
    }
    

    But other than that... no. Stick to either non-generic lists (IList), or use the expected list type.

    0 讨论(0)
  • 2020-12-21 07:37

    It doesn't work because a DalBase<NewType> is not a DalBase<ReplicatedBaseType> - generics do not have co/contra-variance. In C# 4 you can get generic variance, but only on interfaces and delegates.

    0 讨论(0)
提交回复
热议问题