MemberExpression可以返回一个Method

时间:2014-07-08 17:53:52

标签: c# reflection lambda func

我想在C#中使用某种Lambda表达式返回一个方法(或方法信息)。

public class MyClass {
    public object ReturnSomething(string arg, int numericArg)
    {/*...*/}
}

然后,稍后,我想使用像这样的Lambda来引用这个方法..

public static void Run<T>(T sourceObject, Expression<Func<T, object>> memberExpression, IEnumerable<object> parameters)
{
    var methodInfo = ((MemberExpression)memberExpression.Body).Member as MethodInfo;
    if (methodInfo == null)
        throw new ArgumentException("memberExpression must yield a method");
    /*...*/
}

我尝试使用类似的东西:

var myClassObject = new MyClass();
Run(myClassObject, o => o.ReturnSomething, new object["string arg", 1]);

但我一直在我的表达式上得到这个编译错误:

  

无法将方法组“ReturnSomething”转换为非委托类型   '宾语'。你打算调用这个方法吗?

这在c#中是可行的还是我应该放弃并传递一个带有方法名称的字符串并使用反射来查找而不是使用MemberExpression?

1 个答案:

答案 0 :(得分:0)

McKeown问上面正确的问题,当我很容易在lambda表达式中提供参数时,我使用动态执行。

我通过不做哑巴来解决这个问题。我没有返回实际的方法,而是将结构更改为一个执行内联执行的表达式。似乎比我最初去的地方更清洁。

目的是比较两个相似类别对象的执行情况,以确保它们都返回相同的值。这样做是因为我正在重写,并希望确保我的新方法与我的旧方法返回相同。

我最终在这里:

public static void CompareExecutions<TObject, TParameter, TReturn>(this TObject originalSource, TObject alternateSource, IEnumerable<TParameter> parameters, Func<TObject, TParameter, TReturn> testExpression)
    where TObject : class
    where TReturn : class
{
    var originalResults = new List<TReturn>();
    using (new Profile("Original Source"))
        foreach (var parameterSet in parameters)
            originalResults.Add(testExpression(originalSource, parameterSet));

    var alternateResults = new List<TReturn>();
    using (new Profile("Alternate Source"))
        foreach (var parameterSet in parameters)
            alternateResults.Add(testExpression(alternateSource, parameterSet));

    var comparer = new PropertyComparer<TReturn>();
    int errorCount = 0;
    for (int i = 0; i < parameters.Count(); i++)
    {
        if (!comparer.Equals(originalResults[i], alternateResults[i]))
        {
            errorCount++;
            Debug.WriteLine("^--- Mismatch for parameter {0}:\r\n\t{1}", i, string.Join("\r\n\t", parameters.ElementAt(i)));
        }
    }

    if (errorCount > 0)
        Assert.Fail("The results did not match for {0} items", errorCount);
}

我这样用:

public class OriginalClass
{
    public virtual ResultClass MyMethod(string argOne, int argTwo)
    {/*...*/}
}

public class DerivedClass: OriginalClass
{
    public override ResultClass MyMethod(string argOne, int argTwo)
    {/*New implementation of the original code...*/}
}
//[...]
public void TestTheseTwoClasses() {
    var original = new OriginalClass();
    var derivedClass = new DerivedClass();

    original.CompareExecutions(
        derivedClass,
        new[] {
            new {One = "First", Two=1},
            new {One = "Second", Two=2},
            new {One = "Third", Two=3}
        },
        (c,p) => c.MyMethod(p.One, p.Two)
    );
}