It is necessary to call class methods by name (i.e. I know the string with the name of the class method). Found only one more or less suitable way - to use reflection.

public class Simple { public string SimpleMethod(string param1) { return param1; } } //и собственно вызов Simple simple = new Simple(); var method = typeof(Simple).GetMethod("SimpleMethod"); object[] param = new object[] {"Hello World!"}; string result = method.Invoke(sample, param) as string; 

But as I understand from this method performance drops dramatically. Is there a more "elegant solution"?

  • one
    you can still create an Expression and compile it before the call - Grundy
  • one
    How do you if you implement the delegate type method in the Simple class, or even as an extension method? True, you need to know in advance the name of all the necessary methods, and in the body of a delegate type method you use a poor switch - 4per
  • @ 4per is an interesting option, but the methods are different in signature, you have to write your own delegate for each method, if I understand your point correctly - e1s
  • one
    @ e1s, another option, add the dictionary methods that can be called and called from the dictionary - Grundy

1 answer 1

They suggest using System.Linq.Expressions :

 namespace Research.UnitTests { using System; using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Linq; using System.Linq.Expressions; using System.Collections.Generic; using System.Reflection; [TestClass] public class Research { [TestMethod] public void TestWithTiming() { var calculator = new Calculator(); //Получить ссылку на метод "Calculate". MethodInfo methodInfo = typeof(Calculator).GetMethod( "Calculate", new Type[] { typeof(int) }); //Создать параметр. ParameterExpression param = Expression.Parameter(typeof(int), "i"); //Создать "точку вызова". var thisParameter = Expression.Constant(calculator); //Создать выражение для вызова метода. //Если бы метод был статический, то "точка вызова" была бы //лишней. MethodCallExpression methodCall = Expression.Call( thisParameter, methodInfo, param); //Создать лямбда-выражение. Expression<Func<int, string>> lambda = Expression.Lambda<Func<int, string>>( methodCall, new ParameterExpression[] { param } ); //Откомпилировать лямбда-выражение в Func<>. Func<int, string> func = lambda.Compile(); //Замеряем производительность вызова c использованием рефлексии. var watch = new System.Diagnostics.Stopwatch(); watch.Start(); for (int i = 0; i < 1000000; i++) { string result = (string)methodInfo.Invoke(calculator, new object[] { i }); } watch.Stop(); System.Console.WriteLine(watch.ElapsedMilliseconds); //Замеряем производительность вызова по имени. watch = new System.Diagnostics.Stopwatch(); for (int i = 0; i < 1000000; i++) { string result = func(i); } watch.Stop(); Console.WriteLine(watch.ElapsedMilliseconds); //Замеряем производительность прямого вызова. watch = new System.Diagnostics.Stopwatch.StartNew(); for (int i = 0; i < 1000000; i++) { string result = calculator.Calculate(i); } watch.Stop(); Console.WriteLine(watch.ElapsedMilliseconds); } } public class Calculator { public string Calculate(int i) { string result = string.Empty; //Референсный код. DateTime now = DateTime.Now; DateTime nextDay = now.AddDays(i); result = nextDay.ToString(); return result; } } } 

Result:

1930 (reflection)

1530 (expression)

1519 (direct call)