class MyClass { private static Dictionary<string,object> methods; public void Method1() { // Do something. } public void Method2() { // Do something else. } }
现在,我想要的是从类(一个私有方法尚未被创建),取一个包含method-name的字符串,然后点击该方法,简单的.这样做最简单的方法就是查看名称,获取一个名称的方法,然后执行它,但这迫使我多次使用反射.这种私有方法可能被称为数千或数万次,而且需要快速.所以我想出了两个可能的解决方案.你可能会看到我添加了一个包含string->对象的静态字典(用实际类型替换对象,只是写了对象,因为这两个我的例子).然后我会添加一个静态构造函数,通过该类,并将所有的methodinfos添加到方法字典中.然后提出一个问题,在创建一个类的新实例时,我应该为方法创建绑定的代理,并将它们放在非静态私有dict中,或者我应该简单地使用方法字典中的MethodInfo来激发方法?
平均用例将创建10个此类的实例,并且有1000个调用方法,该方法应该触发方法1或方法2,具体取决于它的字符串参数(而不是,switch-case不是一个选项,因为可扩展性如上所述,这是一个简化版本).实现这一目标最有效的方法是什么?
解决方法
反思在现代版本的框架中比以前更快,但它仍然不如简单地调用代理那么快.
class MyClass { static Dictionary<string,MethodInfo> cache = new ... public void InvokeByName(string name) { MethodInfo methodInfo = GetMethodInfoFromCache(name); methodInfo.Invoke(this,new object[] {}); }
当被要求调用由特定实例上的字符串标识的方法作为接收方时,按名称查找方法信息,然后使用给定的接收方调用它.衡量其性能,看看它是否符合您的目标.如果它是,伟大的不要浪费任何更多的宝贵时间,试图使更快的速度已经够快了.
如果这还不够快,那么我会做什么:
class MyClass { static Dictionary<string,Action<MyClass>> cache = new ... public void InvokeByName(string name) { GetActionFromCache(name).Invoke(this); }
那么GetActionFromCache做什么呢?如果缓存中已经有一个动作,我们就完成了.如果没有,则通过Reflection获取MethodInfo.然后使用Expression Tree库构建一个Lambda:
var methodInfo = SomehowGetTheMethodInfo(name); // We're going to build the lambda (MyType p)=>p.<named method here>() var p = Expression.Parameter(typeof(MyType),"p")); var call = Expression.Call(p,methodInfo); var lambda = Expression.Lambda<Action<MyType>>(call,p); var action = lambda.Compile();
现在你有一个可以用实例调用的动作.把东西放在缓存中.
顺便提一句,这是一个令人难以置信的简化的水平,C#4中的“动态”是如何工作的.我们的问题是非常复杂的,因为我们必须处理接收者和任何类型的参数.你比较容易.