【问题标题】:Problem with adding items to a generic list将项目添加到通用列表时出现问题
【发布时间】:2019-04-17 08:23:01
【问题描述】:

我有如下界面

public interface IInterface
{
    int GetId();
}

ClassA 是一个泛型类,但 T 应该实现 IInterface

public class ClassA<T> where T : IInterface {

}

ClassB 实现 IInterface

public class ClassB : IInterface {
    public int GetId() {
        return 1;
    }
}

ClassC 是我的问题所在,即将项目添加到列表中。

public class ClassC {
    List<ClassA<IInterface>> list = new List<ClassA<IInterface>>();    

    public void Add<T>(ClassA<T> item) where T : IInterface {
        list.Add(item);
    }
}

上面的代码给出了以下有意义的错误

cannot convert from 'Program.ClassA<T>' to'Program.ClassA<Program.IInterface>'

问题的核心在于 Add() 方法,我的目标是能够添加任何类型的 ClassA。我不确定如何设计它以实现以下目标

ClassC classC = new ClassC();
ClassA<ClassB> classA = new ClassA<ClassB>();
classC.Add(classA);

有什么想法吗?

【问题讨论】:

标签: c# .net generics


【解决方案1】:

如何使用协变通用类型参数。

public interface IInterface
{
    int GetId();
}

// Contra-variant and covariant generic type argument can be used only in interfaces and delegates
public interface IClassA<out T> where T : IInterface 
{
}

public class ClassA<T> : IClassA<IInterface> where T : IInterface { }

public class ClassB : IInterface
{
    public int GetId()
    {
        return 1;
    }
}

public class ClassC
{
    List<IClassA<IInterface>> list = new List<IClassA<IInterface>>();

    public void Add(IClassA<IInterface> item)
    {
        list.Add(item);
    }
}
public class Test
{
    public static void Run()
    {
        ClassC classC = new ClassC();
        ClassA<ClassB> classA = new ClassA<ClassB>();
        classC.Add(classA);
    }
}

【讨论】:

  • 很高兴它有帮助:)
  • 实际上是Covariance 不是逆变。 (我经常需要检查以确保我也找到了正确的方法)
  • 这些名字令人困惑
  • Eric Lippert 做得很好series on it back in 2007。第一部分描述了为什么一个 co- 和另一个 contra- 处于非常高的级别,但是当我使用真正的 C# 代码时(对我来说)仍然不容易看到它。如果您以前没有阅读过该系列(或想要重新阅读),我会推荐它。
  • 谢谢。我会检查一下。 Jeffrey Richter 在他的“CLR via C#”一书中也解释了这个概念。我可能不得不重读那部分,因为我还不是很清楚。
【解决方案2】:

根据您的设计细节,您可以将ClassA 分成两部分:

public abstract class ClassA {
  //Stuff that only works in terms of IInterface,
  //maybe with some abstract methods, required constructors, etc
}
public class ClassA<T> : ClassA where T : IInterface {
  //Stuff specific to T
}

然后,您将ClassAs 存储在您的列表中,并将它们转换为已知的具体类型,因为/当您知道那是什么并且需要以这些术语工作时(例如,能够调用ClassA&lt;T&gt; 特定功能)

【讨论】:

  • 感谢您抽出宝贵时间回答。我选择了@Darkhan 的解决方案,即使用反变通用类型参数来避免强制转换。
  • 是的,只要你能适应协方差的含义,它就可以工作。
猜你喜欢
  • 1970-01-01
  • 2020-03-02
  • 2020-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-17
  • 2015-12-15
  • 1970-01-01
相关资源
最近更新 更多