我可以避免或优化此动态调用吗?
我想写一个类,它可以处理许多不同类型的输入,所有这些都实现相同的接口。我可以避免或优化此动态调用吗?
我有以下代码:
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
为我的enumerable的每一个迭代。即使我不能完全避免动态调用,是否有任何方法来优化此方法,以便动态调用不再驻留在我的循环中?
它就像你正在使用这个调用最具体的超载(未覆盖)所提供的tile
的DevisePlans
看起来。假设我的理解是正确的(请不要告诉我,如果我错了),那么就使用dynamic
- 它有一个内置的缓存并为此进行了优化:
return spaces.SelectMany(s =>
(IEnumerable<IPlan>)DevisePlans((dynamic)tile, (dynamic)s)
);
和... 就是这样!然而,我会试图寻找一个包含多态性(针对ITile
)或C#4.0方差的答案。
创建一个表达式树(从Expression.Call开始),编译它,并且您将拥有一个快速委托。您应该根据类型缓存委托,以便不会多次编译相同类型的代码。
除非输入内容,否则不能这样做;如果它被键入,'Delegate.CreateDelegate'(在答案中)已经更直接和更快。 – 2012-04-25 20:24:57
你可以编译一个ET,它接受一个对象参数并将其转换为正确的类型。铸造仍然比反思要好。 – fejesjoco 2012-04-25 20:27:16
想一下你在这里找的是visitor pattern。为每种类型定义一个ITileVisitor接口,并为它重载,然后ITile具有一个将访问者作为参数的访问方法。它的Visit的实现将导致调用正确的Devise超载。
访问者模式要求我修改实现'ITile'的类,很遗憾我不能这样做。否则,像这样的事情是我会如何做到的。 – dlras2 2012-04-25 21:04:03
我能说清楚这是什么?有更多特定类型的'DevisePlans'重载的* lot *吗?要么...? – 2012-04-25 20:23:55
你的代码目标有点模糊不清。你能给出一个高层次的概述吗?也许还有另一种方式*给皮肤上皮(可以这么说)。 – user7116 2012-04-25 20:23:58