c# - List<T> 上的 Lambda 并使用反射获取属性名称

标签 c# generics lambda

假设您有一个通用类,它有一个 List<T> Items;

现在想想这个基本的 lambda 表达式:

var result = Items.FindAll(x => x.Name = "Filip");

这只有在我们知道 T 的属性时才有效,当它是泛型类型时你不会这样做。

因此我想像这样使用反射获取属性:

PropertyInfo[] properties = typeof(T).GetProperties(BindingFlags.Public);

并以某种方式将其与上述 Lambda 表达式结合,以便它搜索 Type 的所有公共(public)属性并查看它是否包含“Filip”,此时我不关心属性名称是否为 Name。

这可能吗?

最佳答案

var result = Items.FindAll(x => 
    properties.Any(p => p.PropertyType == typeof(string) && 
                        p.GetValue(x, null) == "Filip"));

显然,这是一个简单的、乐观的字符串比较(例如,您可能想使用 string.Compare),但这应该使思路清晰。

编辑

dtb 在使用表达式树方面提出了一个很好的建议。你可以像这样以更快的方式完成你想要的:

public static class PropertyScanner
{
    static Func<TType, bool> CreatePredicate<TType, TValue>(TValue value, IEqualityComparer<TValue> comparer)
    {
        var arg = Expression.Parameter(typeof(TType), "arg");

        Expression body = null;

        Expression<Func<TValue, TValue, bool>> compare = (val1, val2) => comparer.Equals(val1, val2);

        foreach (PropertyInfo property in typeof(TType).GetProperties(BindingFlags.Public))
        {
            if (property.PropertyType == typeof(TValue) || typeof(TValue).IsAssignableFrom(property.PropertyType))
            {
                Expression prop = Expression.Equal(Expression.Invoke(compare, new Expression[]
                                       {
                                           Expression.Constant(value),
                                           Expression.Property(arg, property.Name)
                                       }),
                                               Expression.Constant(0));

                if (body == null)
                {
                    body = prop;
                }
                else
                {
                    body = Expression.OrElse(body, prop);
                }
            }
        }

        return Expression.Lambda<Func<TType, bool>>(body, arg).Compile();
    }

    public static IEnumerable<TType> ScanProperties<TType, TValue>(this IEnumerable<TType> source, TValue value)
    {
        return ScanProperties<TType, TValue>(source, value, EqualityComparer<TValue>.Default);
    }

    public static IEnumerable<TType> ScanProperties<TType, TValue>(this IEnumerable<TType> source, TValue value, IEqualityComparer<TValue> comparer)
    {
        return source.Where(CreatePredicate<TType, TValue>(value, comparer));
    }
}

这将允许你做这样的事情:

var result = Items.ScanProperties("Filip").ToList();

关于c# - List<T> 上的 Lambda 并使用反射获取属性名称,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2133525/

相关文章:

c# - 如何使用 C# 取消删除文件?

java - 无法在 Java 中创建...的通用数组

c++ - lambda 捕获的 const int 变量的值类别

c# - Django 或 Ruby on Rails

c# - 如何使用响应式(Reactive)扩展同时读取交错文件

c# - 如何动态地将文本框中的数据绑定(bind)到 ListView 中

ios - 如何创建具有符合通用协议(protocol)的弱委托(delegate)的基类?

c# - 带有泛型参数的普通 C# 类无缘无故无法编译

python - 为什么在将 lambda 函数分配给变量时需要用括号括起来?

返回 bool 值的 Python 排序 lambda 函数