【问题标题】:Polymorphism in C# generic typesC# 泛型类型中的多态性
【发布时间】:2017-08-14 04:39:15
【问题描述】:

为什么不能像这样使用泛型?直接为每个具体类型声明公共的开放类型或接口和单独的逻辑:

interface IOpen<T>
{
    T A { get; }
}

class Concrete<int> : IOpen<int>
{
    public int A => 42;
    public string B => "42";
}

interface IWorker<T>
{
    void Do(IOpen<T> item);
}

class WorkerInt : IWorker<int>
{
    public void Do(Concrete<int> item)
    {
        Console.WriteLine(item.A);
        Console.WriteLine(item.B);
    }
}

如何避免上述代码中的限制?如果我创建类ConcreteInt : IOpen&lt;int&gt;,那么WorkerInt 将不会实现IWorker&lt;T&gt;。谢谢。

【问题讨论】:

    标签: c# oop generics


    【解决方案1】:

    您不能用&lt;int&gt; 定义class Concrete&lt;int&gt; - 这就像您试图用一个名为int 的新泛型类型覆盖int 的正常定义。但是在课堂上,您实际上试图返回 int。

    所以它应该是这样的:

    class Concrete : IOpen<int>
    {
        public int A => 42;
        public string B => "42";
    }
    

    但现在WorkerInt 类必须如下所示:

    class WorkerInt : IWorker<int>
    {
        public void Do(Concrete item)
        {
            Console.WriteLine(item.A);
            Console.WriteLine(item.B);
        }
    }
    

    但是IWorker&lt;int&gt; 必须实现void Do(IOpen&lt;T&gt; item),即使Concrete 实现IOpen&lt;T&gt; 你也不能使用void Do(Concrete item),因为它比void Do(IOpen&lt;T&gt; item) 更严格。

    所以你必须这样定义它:

    class WorkerInt : IWorker<int>
    {
        public void Do(IOpen<int> item)
        {
            Console.WriteLine(item.A);
            //Console.WriteLine(item.B);
        }
    }
    

    但这使得item.B 不再起作用,因为IOpen&lt;int&gt; 没有B 属性。

    完成这项工作的唯一方法是将IWorker 更改为:

    interface IWorker<T, R> where T : IOpen<R>
    {
        void Do(T item);
    }
    

    那么WorkerInt可以是这样的:

    class WorkerInt : IWorker<Concrete, int>
    {
        public void Do(Concrete item)
        {
            Console.WriteLine(item.A);
            Console.WriteLine(item.B);
        }
    }
    

    【讨论】:

    • interface IWorker&lt;T, R&gt; where T : IOpen&lt;R&gt; 看起来像一个魔术,它可以在没有严重的代码更改的情况下工作。谢谢。
    【解决方案2】:

    泛型并不是类型推断的占位符。泛型旨在允许List、Dictionary、Tree 等容器包含任何类型,而无需在 Object 之间进行转换。它们使容器在静态方面更加健壮。

    如果您希望能够将有限的一组类型传递给某种处理器,请使用重载方法。

    public void Do(int item) { ... }
    
    public void Do(string item) { ... }
    

    这样,方法签名决定了使用哪种方法。

    此外,如果您尝试创建不同的工作对象,您可以使用一组类似的静态重载方法来实例化工作人员并调用Do() 方法。

    class WorkerManager {
        public static void DoWork(int item) {
            var worker = new WorkerInt();
            worker.Do(item);
        }
    
        public static void DoWork(string item) {
            var worker = new WorkerString();
            worker.Do(item);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-05
      • 2011-07-10
      • 2013-10-11
      • 2017-03-28
      • 1970-01-01
      • 2020-08-06
      • 2017-08-20
      • 1970-01-01
      相关资源
      最近更新 更多