C# 我可以避免或优化这种动态调用吗?

C# 我可以避免或优化这种动态调用吗?,c#,generics,optimization,dynamic,C#,Generics,Optimization,Dynamic,我正在尝试编写一个类,它可以处理许多不同类型的输入,所有这些输入都实现相同的接口 我有以下代码: private IEnumerable<IPlan> DevisePlans(ITile tile, IEnumerable<ISpace> spaces) { MethodInfo method = GetType().GetMethod("DevisePlans", Bindi

我正在尝试编写一个类,它可以处理许多不同类型的输入,所有这些输入都实现相同的接口

我有以下代码:

private IEnumerable<IPlan> DevisePlans(ITile tile, IEnumerable<ISpace> spaces)
{
    MethodInfo method = GetType().GetMethod("DevisePlans",
                                            BindingFlags.NonPublic | BindingFlags.Instance,
                                            null,
                                            new[] {tile.GetType(), typeof(ISpace)},
                                            null);
    var type = typeof(Func<,,>).MakeGenericType(tile.GetType(), typeof(ISpace), typeof(IEnumerable<IPlan>));
    var planner = Delegate.CreateDelegate(type, this, method);
    return spaces.SelectMany(s => (IEnumerable<IPlan>)planner.DynamicInvoke(tile, s));
}

这是可行的,但我正在为我的可枚举项的每个迭代调用
DynamicInvoke
。即使我无法完全避免动态调用,是否有任何方法可以优化此方法,使动态调用不再驻留在我的循环中?

创建一个表达式树(从expression.call开始),编译它,您将拥有一个快速委托。您应该基于类型缓存委托,这样您就不会多次为同一类型编译。

它看起来像是在使用它来调用所提供的
平铺
设计计划
的最特定重载(而不是覆盖)。假设我的理解是正确的(如果我错了,请一定告诉我),然后只使用
动态
-它有一个内置缓存,并为此进行了优化:

return spaces.SelectMany(s =>
    (IEnumerable<IPlan>)DevisePlans((dynamic)tile, (dynamic)s)
);
返回空格。选择many(s=>
(IEnumerable)设备计划((动态)平铺,(动态)s)
);
而且。。。就这样


然而,我很想寻找一个涉及多态性(相对于
ITile
)或C#4.0方差的答案。

认为您在这里寻找的是。为每种类型定义一个带有重载的ITileVisitor接口,然后ITile有一个以访问者为参数的访问方法。它的实现将导致调用正确的design重载。

我可以澄清一下:这是什么调用吗?对于更具体的类型,是否有大量的
developeplan
重载?或者…?至少可以说,你的代码目标有点模糊。你能概括一下吗?也许还有另一种方法可以剥猫的皮(可以这么说),你不能这样做,除非它是打字;如果是键入的,
Delegate.CreateDelegate
(在答案中)已经更直接更快了。您可以编译一个ET,它接受一个对象参数并强制转换为正确的类型。铸造仍然比反射好。这工作非常完美,而且更干净!我需要测试一下它的速度。我在哪里可以找到使用C#4.0方差的解决方案?@Dan关于问题更新/澄清,我认为方差方法不起作用,对不起,为什么要使用
(动态)s
?我的代码编译时没有它-这只是为了让
ISpace
也使用最具体的重载吗?另外,在
SelectMany
中指定类型参数可以避免转换为
IEnumerable
@Dan。老实说,这并不重要<代码>动态
具有传染性-如果调用的一部分是
动态
(即一个参数),则它们都具有传染性。如果你为了清晰起见想把它去掉,那很好。这似乎不正确。根据是否存在
(动态)s
,呼叫的行为会有所不同。(也就是说,如果您有任何依赖于其特定类型的重载函数。)访问者模式要求我修改实现
ITile
的类,不幸的是,我不能这样做。否则我会这样做的。
return spaces.SelectMany(s =>
    (IEnumerable<IPlan>)DevisePlans((dynamic)tile, (dynamic)s)
);