使用泛型的 C# 子类化:我需要一个额外的 ctor 泛型参数,但是怎么做呢?

C# subclassing with generics: I need an extra generic parameter for ctor, but how?

我有一个class

public class LDBList<T> : List<T> where T : LDBRootClass {
    // typical constructor
    public LDBList(LDBList<T> x) : base(x) { }
    ...
}

但我想要一个额外的构造函数,它接受一个不同泛型类型(比如 A)的列表,以及一个将 A 转换为 T 的函数,并从中构建 T 列表,例如

public LDBList(
        Func<A, T> converter, 
        IList<A> aList)
{
    foreach (var x in aList) {
        this.Append(converter(x));
    }
}

所以 converterA->T 类型,所以我使用一个 A 列表并从中创建一个 T 列表。我的 class 由 T 参数化,所以没关系。

但它抱怨“找不到类型或命名空间名称 'A'”。

好的,所以我想它需要 class 上的 A 泛型参数(它真的不喜欢在构造函数上使用它)。但是我把它放在哪里,事实上这甚至可能吗?

理论上,您可以将额外类型添加到 class 本身的通用类型中:

public class LDBList<A, T> : List<T> where T : LDBRootClass
{
    // typical constructor
    public LDBList(LDBList<A, T> x) : base(x) { }

    public LDBList(
        Func<A, T> converter,
        IList<A>   aList)
    {
        foreach (var x in aList)
        {
            this.Append(converter(x));
        }
    }
}

但这当然意味着您需要使用额外的类型参数来声明该类型的实例,除非您使用特定的构造函数,否则您甚至不需要它。所以这样不行。

可以像这样声明一个助手class:

public static class LDBListCreator
{
    public static LDBList<T> CreateFrom<T, A>(Func<A, T> converter, IList<A> aList) where T: LDBRootClass
    {
        var result = new LDBList<T>();
        result.AddRange(aList.Select(converter));
        return result;
    }
}

这假定 LDBList<T> 具有默认构造函数。

但是通过检查,您应该能够看到创建这样一个简单的帮助程序毫无意义 class。如果你添加一个构造函数到你的列表 class 接受 IEnumerable<T> (就像 List<T> class 有)像这样:

public LDBList(IEnumerable<T> items) : base(items)
{
}

然后你可以使用IEnumerable.Select().

构造一个LDBList<T>的实例

例如,给定:

public class LDBRootClass
{
}

public class DerivedLDBRootClass : LDBRootClass
{
    public DerivedLDBRootClass(string value)
    {
        // .. whatever
    }
}

然后您可以非常简单地将 List<string> 转换为 LDBList<DerivedLDBRootClass>,无需任何额外的脚手架,如下所示:

var strings = new List<string> { "One", "Two", "Three", "Four", "Five" };
var result  = new LDBList<DerivedLDBRootClass>(strings.Select(item => new DerivedLDBRootClass(item)));

我认为您不能像那样向构造函数添加额外的泛型类型。

我会重构转换器来创建和return LDBList 的实例,这样转换就充当从 A 的实例创建 LDBList 的工厂。

public class Converter<T,A>
{
    public LDbList<T> CreateLdbList(IList<A>) {
       var list = new LdbList<T>();
       // do the conversion here
       return list;
    }
}

然后,将用法更改为

var Converter<X,Y> = new Converter();
var result = Converter.Convert(originalData);