Очевидно, что никто не может ответить на вопрос, фактически не попробовав его и не выполнив тесты производительности, чтобы увидеть, достигнута ваша цель или нет.
Отражение намного быстрее в современных версиях фреймворка, чем раньше, но все же не так быстро, как простой вызов делегата.
Мое предложение будет начинаться с предложенного вами решения: один раз создайте кэш информации метода:
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? Если в кеше уже есть действие, мы закончили. Если нет, то получите MethodInfo через Reflection. Затем используйте библиотеку Expression Tree для построения лямбды:
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. Наша проблема чрезвычайно усложняется тем, что нам приходится иметь дело с получателем и аргументами, имеющими любой тип. У вас это очень легко сравнительно.