C# 泛型的动态调度性能
我有30多个类用作类C# 泛型的动态调度性能,c#,generics,dynamic,dynamic-dispatch,C#,Generics,Dynamic,Dynamic Dispatch,我有30多个类用作类子类的泛型参数。这里TKind可以是大约30个类中的任意一个类 internal sealed class Child<TKind> : Base { public override void SupplyTo(IBuilder builder) { builder.AddPart((dynamic)this); } } 因为此是泛型类型,编译器无法解析方法重载。因为它不知道是否为这个泛型类型提供了重载 但这将编译,因为我
子类的泛型参数。这里TKind
可以是大约30个类中的任意一个类
internal sealed class Child<TKind> : Base
{
public override void SupplyTo(IBuilder builder)
{
builder.AddPart((dynamic)this);
}
}
因为此
是泛型类型,编译器无法解析方法重载。因为它不知道是否为这个泛型类型提供了重载
但这将编译,因为我们使用的是动态分派,方法重载在运行时得到解决
builder.AddPart((dynamic)this);
我担心表现AddPart
重载可能被调用数千次。编译器在第一次为每个泛型类型解决重载后是否优化了动态部件?它是否知道在该上下文中,此
将始终是相同的类型
每个泛型类型的第一个调用是否只会是昂贵的调用,而其余的调用将类似于直接调用方法重载
让我们举个例子第一种方法:
foreach(Base item in items)
{
builder.AddPart((dynamic)item); // dynamic dispatch
}
我在这里假设编译器不能优化动态调用,因为item
可以是任何东西
第二种方法:
foreach(Base item in items)
{
item.SupplyTo(builder); // double dispatch
}
但在上面的例子中,我们使用的是访问者模式,在每个泛型类中,这个
总是相同的类型。所以在第二种方法中应该有一些优化?这真的很难回答,因为我们不知道您期望的性能是什么。假设运行时进行了一些优化,以便后续调用比第一次调用更快。它仍然没有提供任何关于后续调用是否足够快以满足您的需要的信息(因为它们可能仍然比原始方法调用慢)。另一方面,如果没有进行优化,它可能仍然足够快,可以满足您的需求。长话短说:首先测量,然后决定是否需要任何优化。AddPart的30个重载让我感到困惑。AddPart不能只取一个基类吗?这就是OOP的全部要点。AddPart做了什么,要求它对派生类型具有所有这些重载?使用30个重载是因为我们为每个TKind
编写了单独的算法,所以我们不能使用一个重载共享算法。(另一种方法是简单地打开类型,但我发现double dispatch看起来更干净。)@adambenson但您的基类中是否有一个虚拟DoStuff()方法,该方法在每个派生类型中都会被重写?或者我遗漏了什么:-)Builder类有很多字段,每次调用AddPart时都会修改其中一个字段,其中一些字段在某些情况下会记录错误,我不能为每个TKind
设置DoStuff
,因为这些字段应该在Builder中管理@这真的很难回答,因为我们不知道你期望什么样的表现。假设运行时进行了一些优化,以便后续调用比第一次调用更快。它仍然没有提供任何关于后续调用是否足够快以满足您的需要的信息(因为它们可能仍然比原始方法调用慢)。另一方面,如果没有进行优化,它可能仍然足够快,可以满足您的需求。长话短说:首先测量,然后决定是否需要任何优化。AddPart的30个重载让我感到困惑。AddPart不能只取一个基类吗?这就是OOP的全部要点。AddPart做了什么,要求它对派生类型具有所有这些重载?使用30个重载是因为我们为每个TKind
编写了单独的算法,所以我们不能使用一个重载共享算法。(另一种方法是简单地打开类型,但我发现double dispatch看起来更干净。)@adambenson但您的基类中是否有一个虚拟DoStuff()方法,该方法在每个派生类型中都会被重写?或者我遗漏了什么:-)Builder类有很多字段,每次调用AddPart时都会修改其中一个字段,其中一些字段在某些情况下会记录错误,我不能为每个TKind
设置DoStuff
,因为这些字段应该在Builder中管理@阿丹文森
foreach(Base item in items)
{
item.SupplyTo(builder); // double dispatch
}