【问题标题】:How to implement generic polymorphism in c# - Part 2?如何在 C# 中实现泛型多态性 - 第 2 部分?
【发布时间】:2012-04-18 15:48:45
【问题描述】:

我已经发布了this question with a bad sample

这段代码应该会更好。

为避免混淆,我总结了一些代码:

using System.Collections.Generic;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main()
        {
            IManager<ISpecificEntity> specificManager = new SpecificEntityManager();
            IManager<IAntoherSpecificEntity> anotherSpecificManager = new AnotherSpecificEntityManager();
            Dictionary<string, IManager<IIdentifier>> managers = new Dictionary<string, IManager<IIdentifier>>();
            managers.Add("SpecificManager", (IManager<IIdentifier>)specificManager);
            managers.Add("AnotherSpecificManager", (IManager<IIdentifier>)anotherSpecificManager);

            foreach (var manager in managers.Values)
            {
                IIdentifier entity = manager.Container.GetEntity();
            }
        }
    }

    internal interface IIdentifier
    {
        int Id { get; set; }
    }

    internal interface ISpecificEntity : IIdentifier
    {
        string SpecificValue { get; set; }
    }

    internal class SpecificEntity : ISpecificEntity
    {
        public int Id { get; set; }
        public string SpecificValue { get; set; }
    }


    internal interface IAntoherSpecificEntity : IIdentifier
    {
        string AnotherSpecificValue { get; set; }
    }

    internal class AntoherSpecificEntity : IAntoherSpecificEntity
    {
        public int Id { get; set; }
        public string AnotherSpecificValue { get; set; }
    }

    internal interface IContainer<out TIdentifier> where TIdentifier : IIdentifier
    {
        TIdentifier GetEntity();
    }

    internal interface ISpecificContainer : IContainer<ISpecificEntity>
    {
    }

    internal class SpecificContainer : ISpecificContainer
    {
        public ISpecificEntity GetEntity()
        {
            return new SpecificEntity { SpecificValue = "SpecificValue" };
        }
    }

    internal interface IAnotherSpecificContainer : IContainer<IAntoherSpecificEntity>
    {
    }

    internal class AnotherSpecificContainer : IAnotherSpecificContainer
    {
        public IAntoherSpecificEntity GetEntity()
        {
            return new AntoherSpecificEntity { AnotherSpecificValue = "AnotherSpecificValue" };
        }
    }

    internal interface IManager<TIdentifier> where TIdentifier : IIdentifier
    {
        IContainer<TIdentifier> Container { get; set; }
    }

    internal class SpecificEntityManager : IManager<ISpecificEntity>
    {
        public IContainer<ISpecificEntity> Container { get; set; }
    }

    internal class AnotherSpecificEntityManager : IManager<IAntoherSpecificEntity>
    {
        public IContainer<IAntoherSpecificEntity> Container { get; set; }
    }
}

当我调试代码时,我在第 12 行的 Main() 中收到 InvalidCastException。

我知道ISpecificEntity 实现了IIdentifier。 但显然从IManager&lt;ISpecificEntity&gt; 直接转换为IManager&lt;IIdentifier&gt; 是行不通的。

我认为使用协方差可以解决问题,但将 IManager&lt;TIdentifier&gt; 更改为 IManager&lt;in TIdentifier&gt;IManager&lt;out TIdentifier&gt; 也不起作用。

那么,有没有办法将specificManager 转换为IManager&lt;IIdentifier&gt;

谢谢,一切顺利。

【问题讨论】:

标签: c# generics inheritance casting covariance


【解决方案1】:

首先你对泛型的理解是错误的。

如果你看一下 Foo 它是一个泛型类型。 Foo 和 Foo 是新类型,它们不是从 List 派生的,也不是通过继承连接的类型。 使用泛型创建新类型,它不会派生!

但是,您正在寻找的是Covariance and Contravariance。这将允许您创建一种“泛型多态性”,但为此您需要在泛型定义中指定它。因此,它只适用于极少数开箱即用的框架泛型。

class Program
{
    static void Main(string[] args)
    {
        IManager<IIdentifier> f1 = new C1();
        IManager<IIdentifier> f2 = new SpecificEntityManager(); //IManager<ISpecificEntity>
    }
}

interface IIdentifier { }
interface ISpecificEntity : IIdentifier { }
interface IManager<out T> { }

class C1 : IManager<IIdentifier> { }
class SpecificEntityManager : IManager<ISpecificEntity> { }

这是你必须改变的:

internal interface IContainer<out TIdentifier> where TIdentifier : IIdentifier 
{ 
    TIdentifier GetEntity(); 
}
internal interface IManager<out TIdentifier> where TIdentifier : IIdentifier 
{
    IContainer<IIdentifier> Container { get; }
}
internal class SpecificEntityManager : IManager<ISpecificEntity>
{
    public IContainer<IIdentifier> Container { get; set; }
}
internal class AnotherSpecificEntityManager : IManager<IAntoherSpecificEntity>
{
    public IContainer<IIdentifier> Container { get; set; }
}

【讨论】:

  • 你完全误解了这个问题。
  • 其实我明白了,如果你正确使用语法,它就可以工作。添加了代码示例。
  • 完美!这适用于示例代码。我希望我可以在生产中使用它! ;-) 谢谢,一切顺利!
【解决方案2】:

您不需要 IManager 可以继承的非泛型 IManager。那么 IManager 是一个 IManager 并且可以强制转换?

【讨论】:

  • 如果有 IManager 会继承的通用“ISuperManager”,我如何访问通用属性 Container?
  • 不一定。 IManager 可以从非通用的空 IManager 继承。 IManager 是 IManagers...我认为。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-03
  • 2011-11-07
  • 1970-01-01
相关资源
最近更新 更多