使用泛型的 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));
}
}
所以 converter
是 A->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);
我有一个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));
}
}
所以 converter
是 A->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);