指定“任何子类”在 C# 类型约束中而不是“一个特定子类”
如果我想编写一个采用可变数量的“TDerived”的方法,其中 TDerived 是“Base”类的任何子类,有什么方法可以做到这一点?
以下代码仅适用于单个特定的指定子类:
void doStuff<TDerived>(params TDerived[] args) where TDerived : Base
{
//stuff
}
即,如果我有
class Super { }
class Sub0 : Super { }
class Sub1 : Super { }
,那么我无法执行此操作,
Sub0 s0 = new Sub0();
Sub1 s1 = new Sub1();
doStuff(s0, s1);
因为我得到“最佳重载匹配...有一些无效参数”。
无论编译器如何处理类型约束和可变参数函数,这似乎(据我所知)完全类型安全。我知道我可以进行强制转换,但如果这是类型安全的,为什么不允许它呢?
编辑:
也许一个更有说服力的例子:
void doStuff<TDerived>(params SomeReadOnlyCollection<TDerived>[] args) where TDerived : Base
{
foreach(var list in args)
{
foreach(TDerived thing in list)
{
//stuff
}
}
}
If I would like to write a method that takes a variable number of "TDerived" where TDerived is any subclass of a class "Base", is there any way to do this?
The following code only works with a single specific specified subclass:
void doStuff<TDerived>(params TDerived[] args) where TDerived : Base
{
//stuff
}
ie if I have
class Super { }
class Sub0 : Super { }
class Sub1 : Super { }
then I cannot do
Sub0 s0 = new Sub0();
Sub1 s1 = new Sub1();
doStuff(s0, s1);
since I get "best overloaded match... has some invalid arguments".
Regardless of how the compiler handles the type constraints and variadic functions, this seems (as far as I can tell) completely type-safe. I know I could cast, but if this is type safe why not allow it?
EDIT:
Perhaps a more convincing example:
void doStuff<TDerived>(params SomeReadOnlyCollection<TDerived>[] args) where TDerived : Base
{
foreach(var list in args)
{
foreach(TDerived thing in list)
{
//stuff
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
TDerived
需要能够解析为单一类型。在您的示例中,它可以解析的唯一类型是Super
,但编译器不会实现这一飞跃。您可以让编译器实现这一飞跃。关于您的更新,请考虑(而不是通用方法)定义一个接受
IEnumerable
的方法,该方法将支持派生类型,因为IEnumerable
code> 是协变的(从 .NET 4 开始)。IEnumerable
本质上也是只读和只进的,如果您有foreach
循环,则非常完美。完整的工作示例:IEnumerable
从 .NET 2.0 开始由 BCL 集合实现,包括T[]
、List
、< code>ReadOnlyCollectionHashSet
等。TDerived
needs to be able to resolve to a single type. In your example, the only type it could resolve to would beSuper
, but the compiler is not going to make that leap. You can make that leap for the compiler.Regarding your update, consider (instead of a generic method) defining a method accepting
IEnumerable<ISuper>
, which will support derived types becauseIEnumerable<T>
is covariant (as of .NET 4).IEnumerable<T>
is also inherently readonly and forward-only, perfect if you have aforeach
loop. Full working example:IEnumerable<T>
is implemented by BCL collections since .NET 2.0, includingT[]
,List<T>
,ReadOnlyCollection<T>
,HashSet<T>
, etc.在您的示例中,您实际上是在告诉编译器,
doStuff
的所有参数在编译时必须具有相同类型,并且该类型必须从Base
继承。如果您想允许参数具有不同类型,那么就不要使用泛型:编辑
这同样适用于您的新示例 - 而不是您的特定
SomeReadOnlyCollection
可以使用IEnumerable
,因为它是协变 :In your example, you are actually telling the compiler that all arguments to
doStuff
must be of the same type at compile time, and that this type has to be inherited fromBase
. If you want to allow the arguments to be of different types, then just don't use generics:EDIT
The same applies with your new example - instead of a specific
SomeReadOnlyCollection
you can useIEnumerable
, as it is covariant:好吧,你当然可以更改
为
,然后如果 Super 是 TDerived 就可以了。
我可能会误解您的意思,但使方法采用基类的任何子类的唯一方法是声明该方法以采用对基类型的引用。
Well you could most certainly change
To
and then it would work if Super is TDerived.
I may be misunderstanding you, but the only way to make a method take any subclass of a base class is to declare the method to take a reference to the base type.
您可以使用的另一种替代方法是简单地显式指定通用参数。例如:
您应该能够对
SomeReadOnlyCollection
的情况应用相同的原则,只要它是 协变。例如,IEnumerable
就是这样一个集合:One other alternative you could use is to simply specify the generic parameter explicitly. For example:
You should be able to apply the same principle on the case with
SomeReadOnlyCollection
, as long as it is covariant. For example,IEnumerable
is such a collection: