简体   繁体   English

使用LINQ进行反射而无需for或foreach

[英]Reflection with LINQ without for or foreach

I'm trying to filter a list of objects based on specific properties via reflection. 我正在尝试通过反射基于特定属性过滤对象列表。 The problem is I can't find a way to do it without a for or foreach loop. 问题是,如果没有for或foreach循环,我找不到解决方法。 Not that there's anything wrong with that, but I'd like to use LINQ to capture the object I'm filtering for instead. 并不是说这有什么问题,但我想使用LINQ来捕获要过滤的对象。

string prop = 'SortOrder';
string propVal = '1';
PropertyInfo result;
//StackObject is passed in and can contain over a million objects
var objList = (StackObject as IEnumerable).Cast<object>().ToList();

foreach (var obj in objList)
{
    PropertyInfo filterProperty = obj.GetType().GetProperty(prop);

    if (filterProperty.GetValue(obj, null).ToString() == propVal)
    {
        result = (PropertyInfo)obj;
        return result;
    }
}

I have tried this: 我已经试过了:

var objList = (StackObject as IEnumerable).Cast<object>().ToList();
PropertyInfo desiredObject = (PropertyInfo)objList.Where(o => o.GetType().GetProperty(prop).GetValue(o, null).ToString() == propVal);

But I keep getting a list of objects or null instead of the specific object. 但是我一直在获取对象列表或null而不是特定对象。 The end goal is to be more performant (as the list of objects can grow quite large at times) and filter appropriately for a given property. 最终目标是提高性能(因为对象列表有时可能会变得非常大)并针对给定的属性进行适当的过滤。

You would want to use Select to get your initial property info along with the object. 您可能希望使用Select来获取您的初始属性信息以及该对象。 You can then filter to all of the matches with Where , or to the first match with FirstOrDefault . 然后,您可以使用Where过滤所有匹配项,或者使用FirstOrDefault第一个匹配FirstOrDefault

Something like this should work: 这样的事情应该起作用:

var result = (StackObject as IEnumerable)
    .Cast<object>()
    .Select(obj => (Obj: obj, Prop: obj.GetType().GetProperty(prop)))
    .FirstOrDefault(tup => tup.Prop?.GetValue(tup.Obj, null)?.ToString() == propVal)
    ?.Prop;

This is utilizing a tuple of the object and the property within the select syntax so that your later filtering has access to both. 这将利用select语法中的对象和属性的元组,以便您以后的过滤可以访问这两者。 The same predicate in the FirstOrDefault should work for a Where should you want to get all matches. 在相同的谓词FirstOrDefault应该为工作Where ,你应该想获得的所有比赛。

As an alternative to tuples, you could use an anonymous object. 作为元组的替代,您可以使用匿名对象。 With an anonymous object, you may get something like this: 使用匿名对象,您可能会得到以下信息:

var result = (StackObject as IEnumerable)
    .Cast<object>()
    .Select(obj => new { Obj = obj, Prop = obj.GetType().GetProperty(prop)} )
    .FirstOrDefault(item => item.Prop?.GetValue(item.Obj, null)?.ToString() == propVal)
    ?.Prop;

If you wanted to use Where , you would need an additional Select to get the item => item.Prop values from the filtered enumerable. 如果要使用Where ,则需要额外的Select来获取item => item.Prop值,该值来自已过滤的枚举。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM