如何使用表达式调用实例方法

本文关键字:实例方法 调用 表达式 何使用 | 更新日期: 2023-09-27 17:54:38

例如,我有一些类的一些属性:

public class SomeClass
{
    public Version Version { get; set; }
}

我有一个带有示例数据的列表:

var list = new List<SomeClass>();
for (var i = 0; i < 1000; i++)
{
    list.Add(new SomeClass
    {
        Version = new Version(i, i / 2, i / 3, i / 4),
    });
}

我想写一个使用version按版本过滤的方法。=方法:

var filterValue = new Version(12, 6, 4, 3);
var modelType = typeof(SomeClass);
var propertyType = typeof(Version);
var arg = Expression.Parameter(modelType, "x");
var property = Expression.Property(arg, "Version");
var value = Expression.Convert(Expression.Constant(filterValue), propertyType);
var versionEqualsMethod = typeof(Version).GetMethod("Equals", new[] { typeof(Version) });
/////////
Expression inst = null; // <-- ???
/////////
var expr = Expression.Call(inst, versionEqualsMethod, property, value);
var delegateType = typeof(Func<,>).MakeGenericType(modelType, typeof(bool));
var delegateValue = Expression.Lambda(delegateType, expr, arg).Compile();
var genericMethod =
    typeof(Enumerable).GetMethods()
        .First(
            method =>
                method.Name == "Where" && method.IsGenericMethodDefinition
                && method.GetGenericArguments().Length == 1 && method.GetParameters().Length == 2)
        .MakeGenericMethod(modelType);
var result = genericMethod.Invoke(null, new object[] { list, delegateValue });

我在Expression.Call中使用什么作为实例?

解决方案是:

var expr = Expression.Call(property, versionEqualsMethod, value);

如何使用表达式调用实例方法

你通常会这样做:

var filterValue = new Version(12, 6, 4, 3);
var modelType = typeof(SomeClass);
var propertyType = typeof(Version);
var arg = Expression.Parameter(modelType, "x");
var property = Expression.Property(arg, "Version");
// Changes from here onward
var value = Expression.Constant(filterValue);
var versionEqualsMethod = typeof(Version).GetMethod("Equals", new[] { typeof(Version) });
var expr = Expression.Call(property, versionEqualsMethod, value);

因为Equals可以这样使用:

model.Version.Equals(filterValue);

我是不是处理model.Version == null的情况!

请注意,您不需要Expression.Convert

如果"包含方法"(您将放置此代码的方法)是非泛型的,则您正在做的事情是可以的,但通常它将是泛型方法,其泛型参数为modelType,因此代码的最后一部分将不同(从var delegateType =开始),因为您可以直接使用TModelType泛型。

也许我错过了什么,但这不是工作吗:

var results = list.Where(sc => sc.Version == filterVersion);

你想要完成的事情用反射来做要容易得多。查看这个在线运行的示例。如果我没理解错的话,那是……如果你能提供你正在编写的函数的签名,那将会很有帮助。)

实施

public static class Extensions
{
    public static IEnumerable<T> Filter<T>(
        this IEnumerable<T> enumerable, string propertyName, object filterValue)
    {
        var elementType = typeof (T);
        var property = elementType.GetProperty(propertyName);
        return enumerable.Where(element =>
        {
            var propertyValue = property.GetMethod.Invoke(element, new object[] {});
            return propertyValue.Equals(filterValue);
        });
    }
}
使用

var list = new List<SomeClass>();
for (var i = 0; i < 1000; i++)
{
    list.Add(new SomeClass {Version = new Version(i, i/2, i/3, i/4)});
}
var filteredList = list.Filter("Version", new Version(12, 6, 4, 3));
Console.WriteLine(filteredList.Single().Version);