Получить имя универсального метода внутри прокси-класса

#c# #generics #interface

#c# #общие методы #интерфейс

Вопрос:

Я хотел бы создать прокси-класс, который сможет извлекать имя метода, указанного в аргументе, и экземпляр параметра с универсальным завершением (иначе говоря, мне не нужны nameof() или волшебные строки).

Например, я хотел бы иметь возможность делать что-то вроде

 public interface ITestInterface
{
    void TestMethod(Param myParam) 
}

var proxy = new Proxy<ITestInterface>();
var param = new Param();
proxy.WriteName(x => ITestInterface.TestMethod(param));
  

и прокси-класс должен иметь возможность повторно запрашивать имя метода и выполнять tostring для экземпляра параметра :

 public class Proxy<T>
{
    public void WriteName(Something something)
    {
        Console.WriteLine(something.MethodName); // write "TestMethod"
        Console.WriteLine(something.Parameter.ToString()); // use the tostring of the instance object
    }
}
  

Спасибо за вашу помощь

Ответ №1:

Я бы сказал, что было бы нелегко поддерживать все возможные сценарии, но для того, что вы описали в вопросе, вы можете попробовать использовать деревья выражений:

 public class Proxy<T>
{
    public void WriteName(Expression<Action<T>> something)
    { 
        // TODO: add correct handling for not supported operations
        if (something.Body is MethodCallExpression mc)
        {
            Console.WriteLine(mc.Method.Name);
            foreach (var arg in mc.Arguments)
            {
                if (arg is MemberExpression me amp;amp; me.Expression is ConstantExpression cnst)
                {
                    var val = me.Member.MemberType switch
                    {
                        MemberTypes.Field => ((FieldInfo)me.Member).GetValue(cnst.Value),
                        MemberTypes.Property => ((PropertyInfo)me.Member).GetValue(cnst.Value),
                        _ => null 
                    };
                    Console.WriteLine(val);
                }
            }
        }
    }
}
  

И использование:

 var proxy = new Proxy<ITestInterface>();
var param = new Param();
proxy.WriteName(t => t.TestMethod(param)); // actually many more can be passed here
  

Ответ №2:

Если я правильно понимаю, вы можете попробовать это:

 public class Proxy<T>
{
    public void WriteName(Expression<Action> action)
    {
        var methodCallExp = (MethodCallExpression)action.Body;

        Console.WriteLine(methodCallExp.Arguments.First().ToString());
        Console.WriteLine(methodCallExp.Method.Name);
    }
}
  

и вызвать прокси-класс следующим образом:

       var proxy = new Proxy<ITestInterface>();
      proxy.WriteName(() => new ConcreteTestInterface().TestMethod(param));