我可以避免或优化此动态调用吗?

时间:2012-04-25 20:18:40

标签: c# generics optimization dynamic

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

我有以下代码:

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));
}

类中有许多DevisePlans的实现,每个实现都有第一个实现ITile的参数类型。

private IEnumerable<IPlan> DevisePlans(Foo tile, ISpace space) { /* ... */ }
private IEnumerable<IPlan> DevisePlans(Bar tile, ISpace space) { /* ... */ }

这样可行,但我可以为我的可枚举的每一次迭代调用DynamicInvoke。即使我无法完全避免动态调用,有没有办法优化此方法,以便动态调用不再驻留在我的循环中?

3 个答案:

答案 0 :(得分:5)

看起来像,就像您使用它来为DevisePlans提供的tile调用最具体的重载(不覆盖)。假设我的理解是正确的(请告诉我,如果我错了),那么只需使用dynamic - 它有一个内置缓存并针对此进行了优化:

return spaces.SelectMany(s =>
    (IEnumerable<IPlan>)DevisePlans((dynamic)tile, (dynamic)s)
);

和... 就是它

但是,我会想要寻找一个涉及多态(针对ITile)或C#4.0方差的答案。

答案 1 :(得分:0)

创建一个表达式树(以Expression.Call开头),编译它,你将拥有一个快速委托。您应该根据类型缓存委托,这样您就不会多次编译相同的类型。

答案 2 :(得分:0)

在这里想想你正在寻找的是visitor pattern。使用每种类型的重载定义ITileVisitor接口,然后ITile有一个Visit方法,它将访问者作为参数。它实现了Visit,这将导致调用正确的Devise重载。