如何正确使用C#中相关但不同类的调用方法

Aar*_*oin 11 c# oop generics static-typing

说实话,我不知道怎么说这个问题所以请原谅我,如果实际问题不是你所期望的基于标题.C#是我编写过的第一个静态类型的语言,到目前为止,它对我来说是一个绝对头疼的问题.我很确定我对于如何以静态类型的方式设计系统的核心思想没有很好的处理.

这是我想要做的一个粗略的想法.假设我有一个类的层次结构,如下所示:

abstract class DataMold<T>
{
    public abstract T Result { get; }
}

class TextMold : DataMold<string>
{
  public string Result => "ABC";
}  

class NumberMold : DataMold<int>
{
   public int Result => 123
}
Run Code Online (Sandbox Code Playgroud)

现在假设我想要列出项目列表,其中项目可以是任何类型的模具,我可以Resultforeach循环中获取每个项目的属性,如下所示:

List<DataMold<T>> molds = new List<DataMold<T>>();
molds.Add(new TextMold());
molds.Add(new NumberMold());

foreach (DataMold<T> mold in molds)
    Console.WriteLine(mold.Result);
Run Code Online (Sandbox Code Playgroud)

正如您可能已经知道的那样,这不起作用.从我在搜索中看到的内容来看,它与我无法将List声明为类型这一事实有关DataMold<T>.这样做的正确方法是什么?

Joh*_* Wu 11

简短的回答:你做不到.

关于泛型类型的违反直觉的一个原因是它们不相关.List<int>例如,A 与a无任何关系List<string>.它们不会相互继承,也不能将它们相互转换.

可以声明一个协方差关系,它看起来很像一个继承关系,但不是在您声明的一个int和一个之间string,因为一个是值类型而另一个是引用类型.

您唯一的选择是添加他们共同的另一个界面,如下所示:

interface IDataMold
{
}

abstract class DataMold<T> : IDataMold
{
    public abstract T Result { get; }
}
Run Code Online (Sandbox Code Playgroud)

现在您可以将所有模具存放在一个List<IDataMold>.但是,界面没有属性,所以你有一个heckuva时间从中得到任何东西.您可以添加一些属性,但它们不是特定于类型的,因为IDataMold没有泛型类型参数.但是你可以添加一个共同的属性

interface IDataMold
{
    string ResultString { get; }
}
Run Code Online (Sandbox Code Playgroud)

......并实施它:

abstract class DataMold<T>
{
    public abstract T Result { get; }
    public string ResultString => Result.ToString();
}
Run Code Online (Sandbox Code Playgroud)

但是如果你唯一需要为每个项目显示一个等价的字符串,你可以改写ToString():

class TextMold : DataMold<string>
{
    public string Result => "ABC";
    public override string ToString() => Result.ToString();
}
Run Code Online (Sandbox Code Playgroud)

现在你可以这样做:

List<IDataMold> molds = new List<IDataMold>();
molds.Add(new TextMold());
molds.Add(new NumberMold());

foreach (var mold in molds)
{
    Console.WriteLine(mold.ToString());
}
Run Code Online (Sandbox Code Playgroud)