如何使用Expression调用实例的方法

时间:2015-06-09 07:18:27

标签: c#

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

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.Equals方法按版本过滤的方法:

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);

3 个答案:

答案 0 :(得分:4)

你通常会这样做:

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

如果&#34;包含方法&#34;你正在做的事情是好的。 (你将此代码放在这里的方法)是非泛型的,但通常它是一个通用方法,它具有通用参数modelType,所以代码的最后部分会有所不同(从var delegateType =开始),因为您可以直接使用TModelType泛型类型。

答案 1 :(得分:0)

也许我错过了某些东西,但这不会起作用:

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

答案 2 :(得分:0)

你想要完成的事情更容易用反射做。检查this running online example。 (如果我理解正确的话......如果你能提供你想写的功能的签名,那会很有帮助。)

<强>实施

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);