C# 指明;“任何子类”;在C类型约束中,而不是;一个特殊的子类";
如果我想写一个方法,它接受一个变量“TDerived”,其中TDerived是类“Base”的任何子类,有什么方法可以做到这一点吗 以下代码仅适用于单个特定的指定子类:C# 指明;“任何子类”;在C类型约束中,而不是;一个特殊的子类";,c#,polyvariadic,C#,Polyvariadic,如果我想写一个方法,它接受一个变量“TDerived”,其中TDerived是类“Base”的任何子类,有什么方法可以做到这一点吗 以下代码仅适用于单个特定的指定子类: void doStuff<TDerived>(params TDerived[] args) where TDerived : Base { //stuff } 那我就不行了 Sub0 s0 = new Sub0(); Sub1 s1 = new Sub1(); doStuff(s0, s1); 因为我得
void doStuff<TDerived>(params TDerived[] args) where TDerived : Base
{
//stuff
}
那我就不行了
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
}
}
}
class Program
{
static void Main()
{
var sub0s = new Sub0[] { new Sub0() };
var sub1s = new List<Sub1> { new Sub1() };
doStuff(sub0s, sub1s);
}
static void doStuff(params IEnumerable<ISuper>[] args)
{
foreach (var sequence in args)
{
foreach (var obj in sequence)
{
Console.WriteLine(obj.GetType());
// you have the ability to invoke any method or access
// any property defined on ISuper
}
}
}
}
interface ISuper { }
class Super : ISuper { }
class Sub0 : Super { }
class Sub1 : Super { }
void doStuff(参数SomeReadOnlyCollection[]args),其中TDerived:Base
{
foreach(参数中的变量列表)
{
foreach(列表中的派生对象)
{
//东西
}
}
}
你当然可以改变
Sub0 s0 = new Sub0();
Sub1 s1 = new Sub1();
到
如果Super被证明是有效的
我可能误解了你的意思,但是让方法接受基类的任何子类的唯一方法是声明方法引用基类。在你的例子中,你实际上是在告诉编译器,
doStuff
的所有参数在编译时必须是同一类型的,并且该类型必须从Base
继承。如果希望允许参数具有不同的类型,则不要使用泛型:
void doStuff(params Base[] args)
{}
编辑
这同样适用于您的新示例-您可以使用IEnumerable
,而不是特定的SomeReadOnlyCollection
,如下所示:
void doStuff(参数IEnumerable[]args)
{
foreach(参数中的变量列表)
{
foreach(列表中的变量)
{
}
}
}
t派生的
需要能够解析为单个类型。在您的示例中,它可以解析为的唯一类型是Super
,但编译器不会做出这种飞跃。您可以为编译器实现这一飞跃
doStuff(new Super[] { s0, s1 });
doStuff<Super>(s0, s1);
IEnumerable
是自.NET 2.0以来由BCL集合实现的,包括T[]
,List
,ReadOnlyCollection
,HashSet
,等等。您可以使用的另一种方法是简单地显式指定泛型参数。例如:
var s0 = new Sub0();
var s1 = new Sub1();
doStuff<Super>(s0, s1);
调用函数时只需隐式指定基类型:doStuff(s0,s1);增加了一个更复杂的例子
doStuff(new Super[] { s0, s1 });
doStuff<Super>(s0, s1);
class Program
{
static void Main()
{
var sub0s = new Sub0[] { new Sub0() };
var sub1s = new List<Sub1> { new Sub1() };
doStuff(sub0s, sub1s);
}
static void doStuff(params IEnumerable<ISuper>[] args)
{
foreach (var sequence in args)
{
foreach (var obj in sequence)
{
Console.WriteLine(obj.GetType());
// you have the ability to invoke any method or access
// any property defined on ISuper
}
}
}
}
interface ISuper { }
class Super : ISuper { }
class Sub0 : Super { }
class Sub1 : Super { }
var s0 = new Sub0();
var s1 = new Sub1();
doStuff<Super>(s0, s1);
static void doStuff2<TDerived>(params IEnumerable<TDerived>[] args) where TDerived : Super {
// ...
}
// ...
var l0 = new List<Sub0>();
var l1 = new List<Sub1>();
doStuff2<Super>(l0, l1);