简体   繁体   English

带有泛型的 C# 子类化:我需要一个额外的 ctor 泛型参数,但是如何?

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

I have a class我有一堂课

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

but I want to have an extra constructor that takes a list of a different generic type (say A), and a function that converts an A to a T, and build the T list from that, something like但我想要一个额外的构造函数,它接受一个不同泛型类型(比如 A)的列表,以及一个将 A 转换为 T 的函数,然后从中构建 T 列表,例如

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

so converter is of type A->T so I take an A list and make a T list from it.所以converterA->T类型,所以我取一个A列表并从中制作一个T列表。 My class is parameterised by T so that's fine.我的班级由T参数化,所以很好。

But it's complaining "The type or namespace name 'A' could not be found".但它抱怨“找不到类型或命名空间名称'A'”。

OK, so it needs the an A generic parameter on the class I suppose (it really doesn't like it on the constructor).好的,所以它需要在我想的类上有一个A泛型参数(它在构造函数上真的不喜欢它)。 But where do I put it, in fact is this even possible?但我把它放在哪里,事实上这甚至可能吗?

In theory you could add the extra type to the generic types for the class itself:理论上,您可以将额外类型添加到类本身的泛型类型中:

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));
        }
    }
}

But of course that means that you need to declare the instances of that type with an extra type parameter that you won't even need unless you're using that specific constructor.但这当然意味着您需要使用额外的类型参数声明该类型的实例,除非您使用该特定构造函数,否则您甚至不需要该类型参数。 So that's no good.所以这不好。

You could declare a helper class like so:可以像这样声明一个辅助类:

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;
    }
}

This assumes that LDBList<T> has a default constructor.这假设LDBList<T>具有默认构造函数。

But on inspection, you should be able to see that it's pointless creating such a simple helper class.但是经过检查,您应该能够看到创建这样一个简单的帮助类是毫无意义的。 If you add a constructor to your list class that accepts an IEnumerable<T> (like the List<T> class has) like so:如果您向接受IEnumerable<T> (如List<T>类具有)的列表类添加构造函数,如下所示:

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

Then you can construct an instance of LDBList<T> just by using IEnumerable.Select() .然后,您可以仅使用IEnumerable.Select()构造LDBList<T>的实例。

For example, given:例如,给定:

public class LDBRootClass
{
}

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

Then you could convert from a List<string> to a LDBList<DerivedLDBRootClass> very simply without any additional scaffolding, like so:然后,您可以非常简单地从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)));

I don't believe you can add additional generic types to a constructor like that that.我不相信您可以向这样的构造函数添加其他泛型类型。

I would refactor the converter to do the creation and return the instance of LDBList, that way the convert acts as a factory for creating LDBLists from instances of A.我会重构转换器以进行创建并返回 LDBList 的实例,这样转换器充当从 A 的实例创建 LDBLists 的工厂。

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

then, change the usage to be然后,将用法更改为

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM