C# 具有嵌套属性值反射的LINQ
我希望创建一个基于嵌套属性的Linq 假设这是我的项目:C# 具有嵌套属性值反射的LINQ,c#,.net,linq,reflection,propertyinfo,C#,.net,Linq,Reflection,Propertyinfo,我希望创建一个基于嵌套属性的Linq 假设这是我的项目: public class Car { public Engine Engine { get; set; } } public class Engine { public int HorsePower { get; set; } } var myCar = new Car() { Engine = new Engine() { HorsePower = 400 } }; 我使用在某处找到
public class Car {
public Engine Engine { get; set; }
}
public class Engine {
public int HorsePower { get; set; }
}
var myCar = new Car() {
Engine = new Engine() {
HorsePower = 400
}
};
我使用在某处找到的代码,它允许创建表达式
private Expression<Func<TItem, bool>> PropertyEquals<TItem, TValue>( PropertyInfo property, TValue value ) {
var param = Expression.Parameter( typeof( TItem ) );
var memberExp = Expression.Property( param, property );
BinaryExpression body;
//If nullable, Expression.Equal won't work even if the value is not null. So we convert to non nullable (the compared expression)
Type typeIfNullable = Nullable.GetUnderlyingType( memberExp.Type );
if ( typeIfNullable != null ) {
var convertedExp = Expression.Convert( memberExp, Expression.Constant( value ).Type );
body = Expression.Equal( convertedExp, Expression.Constant( value ) );
} else {
body = Expression.Equal( memberExp, Expression.Constant( value ) );
}
return Expression.Lambda<Func<TItem, bool>>( body, param );
}
差不多
var property = GetPropertyForDotSequence( typeof( Car ), "Engine.HorsePower" );
.Select( PropertyEquals<TEntity, int>( property , 400 ) );
您可以使用此方法从嵌套属性名称为
字符串的对象
获取属性
值
public static object GetNestedPropertyValue(object obj, string nestedDottedPropertyName)
{
foreach (String part in nestedDottedPropertyName.Split('.'))
{
if (obj == null)
return null;
PropertyInfo info = obj.GetType().GetProperty(part);
if (info == null)
return null;
obj = info.GetValue(obj, null);
}
return obj;
}
但这是无效的Linq
语句
var engine = myCar.Select( c => c.Engine.HorsePower == 400 );
你可以做的是,如果你有一个像这样的汽车物体
var myCar = new Car()
{
Engine = new Engine()
{
HorsePower = 400
}
};
var myCar2 = new Car()
{
Engine = new Engine()
{
HorsePower = 800
}
};
var cars = new List<Car> { myCar, myCar2 }; //myCar defined above
public static partial class Utils
{
public static Expression<Func<TItem, bool>> PropertyEquals<TItem, TValue>(string propertyPath, TValue value)
{
var source = Expression.Parameter(typeof(TItem), "source");
var propertyNames = propertyPath.Split('.');
var member = Expression.Property(source, propertyNames[0]);
for (int i = 1; i < propertyNames.Length; i++)
member = Expression.Property(member, propertyNames[i]);
Expression left = member, right = Expression.Constant(value, typeof(TValue));
if (left.Type != right.Type)
{
var nullableType = Nullable.GetUnderlyingType(left.Type);
if (nullableType != null)
right = Expression.Convert(right, left.Type);
else
left = Expression.Convert(left, right.Type);
}
var body = Expression.Equal(left, right);
var expr = Expression.Lambda<Func<TItem, bool>>(body, source);
return expr;
}
}
var predicate = Utils.PropertyEquals<Car, int>("Engine.HorsePower", 400);
bool result = predicate.Compile().Invoke(myCar);
List<Car> cars = new List<Car> { myCar };
var cars400 = cars.WherePropertyEquals("Engine.HorsePower", 400).ToList();
您可以根据需要获取发动机马力的值
var horsePower = (int)GetNestedPropertyValue(myCar, "Engine.HorsePower");
var car400 = cars.FirstOrDefault(c => (int)GetNestedPropertyValue(c, "Engine.HorsePower") == 400); //=> myCar
var horsePowers = cars.Select(c => (int)GetNestedPropertyValue(c, "Engine.HorsePower")); //=> 400, 800
编辑
对于Linq
示例,如果您有这样一个列表
var myCar = new Car()
{
Engine = new Engine()
{
HorsePower = 400
}
};
var myCar2 = new Car()
{
Engine = new Engine()
{
HorsePower = 800
}
};
var cars = new List<Car> { myCar, myCar2 }; //myCar defined above
public static partial class Utils
{
public static Expression<Func<TItem, bool>> PropertyEquals<TItem, TValue>(string propertyPath, TValue value)
{
var source = Expression.Parameter(typeof(TItem), "source");
var propertyNames = propertyPath.Split('.');
var member = Expression.Property(source, propertyNames[0]);
for (int i = 1; i < propertyNames.Length; i++)
member = Expression.Property(member, propertyNames[i]);
Expression left = member, right = Expression.Constant(value, typeof(TValue));
if (left.Type != right.Type)
{
var nullableType = Nullable.GetUnderlyingType(left.Type);
if (nullableType != null)
right = Expression.Convert(right, left.Type);
else
left = Expression.Convert(left, right.Type);
}
var body = Expression.Equal(left, right);
var expr = Expression.Lambda<Func<TItem, bool>>(body, source);
return expr;
}
}
var predicate = Utils.PropertyEquals<Car, int>("Engine.HorsePower", 400);
bool result = predicate.Compile().Invoke(myCar);
List<Car> cars = new List<Car> { myCar };
var cars400 = cars.WherePropertyEquals("Engine.HorsePower", 400).ToList();
为了实现您的目标,与其使用单独的帮助函数从属性路径中提取最后一个属性信息,然后将属性信息传递给您的函数,所有这些都应该在函数本身内部完成,即它应该接收包含属性路径的字符串
,如下所示
var myCar = new Car()
{
Engine = new Engine()
{
HorsePower = 400
}
};
var myCar2 = new Car()
{
Engine = new Engine()
{
HorsePower = 800
}
};
var cars = new List<Car> { myCar, myCar2 }; //myCar defined above
public static partial class Utils
{
public static Expression<Func<TItem, bool>> PropertyEquals<TItem, TValue>(string propertyPath, TValue value)
{
var source = Expression.Parameter(typeof(TItem), "source");
var propertyNames = propertyPath.Split('.');
var member = Expression.Property(source, propertyNames[0]);
for (int i = 1; i < propertyNames.Length; i++)
member = Expression.Property(member, propertyNames[i]);
Expression left = member, right = Expression.Constant(value, typeof(TValue));
if (left.Type != right.Type)
{
var nullableType = Nullable.GetUnderlyingType(left.Type);
if (nullableType != null)
right = Expression.Convert(right, left.Type);
else
left = Expression.Convert(left, right.Type);
}
var body = Expression.Equal(left, right);
var expr = Expression.Lambda<Func<TItem, bool>>(body, source);
return expr;
}
}
var predicate = Utils.PropertyEquals<Car, int>("Engine.HorsePower", 400);
bool result = predicate.Compile().Invoke(myCar);
List<Car> cars = new List<Car> { myCar };
var cars400 = cars.WherePropertyEquals("Engine.HorsePower", 400).ToList();
公共静态部分类Utils
{
公共静态表达式PropertyQuals(字符串propertyPath、TValue值)
{
var source=表达式参数(typeof(TItem),“source”);
var propertyNames=propertyPath.Split('.');
var member=Expression.Property(源,propertyNames[0]);
for(int i=1;i
我不太确定它如何有用,因为签名不允许推断泛型类型,所以它需要类似这样的东西
var myCar = new Car()
{
Engine = new Engine()
{
HorsePower = 400
}
};
var myCar2 = new Car()
{
Engine = new Engine()
{
HorsePower = 800
}
};
var cars = new List<Car> { myCar, myCar2 }; //myCar defined above
public static partial class Utils
{
public static Expression<Func<TItem, bool>> PropertyEquals<TItem, TValue>(string propertyPath, TValue value)
{
var source = Expression.Parameter(typeof(TItem), "source");
var propertyNames = propertyPath.Split('.');
var member = Expression.Property(source, propertyNames[0]);
for (int i = 1; i < propertyNames.Length; i++)
member = Expression.Property(member, propertyNames[i]);
Expression left = member, right = Expression.Constant(value, typeof(TValue));
if (left.Type != right.Type)
{
var nullableType = Nullable.GetUnderlyingType(left.Type);
if (nullableType != null)
right = Expression.Convert(right, left.Type);
else
left = Expression.Convert(left, right.Type);
}
var body = Expression.Equal(left, right);
var expr = Expression.Lambda<Func<TItem, bool>>(body, source);
return expr;
}
}
var predicate = Utils.PropertyEquals<Car, int>("Engine.HorsePower", 400);
bool result = predicate.Compile().Invoke(myCar);
List<Car> cars = new List<Car> { myCar };
var cars400 = cars.WherePropertyEquals("Engine.HorsePower", 400).ToList();
var谓词=Utils.PropertyEquals(“引擎马力”,400);
bool result=predicate.Compile().Invoke(myCar);
IMO如果结合以下扩展方法使用,将非常有用
public static partial class Utils
{
public static IQueryable<T> WherePropertyEquals<T, TValue>(this IQueryable<T> source, string propertyPath, TValue value)
{
return source.Where(PropertyEquals<T, TValue>(propertyPath, value));
}
public static IEnumerable<T> WherePropertyEquals<T, TValue>(this IEnumerable<T> source, string propertyPath, TValue value)
{
return source.Where(PropertyEquals<T, TValue>(propertyPath, value).Compile());
}
}
公共静态部分类Utils
{
公共静态IQueryable WherePropertyEquals(此IQueryable源、字符串propertyPath、TValue值)
{
返回source.Where(PropertyQuals(propertyPath,value));
}
公共静态IEnumerable WherePropertyEquals(此IEnumerable源、字符串propertyPath、TValue值)
{
返回source.Where(PropertyQuals(propertyPath,value.Compile());
}
}
所以你可以写这样的东西
var myCar = new Car()
{
Engine = new Engine()
{
HorsePower = 400
}
};
var myCar2 = new Car()
{
Engine = new Engine()
{
HorsePower = 800
}
};
var cars = new List<Car> { myCar, myCar2 }; //myCar defined above
public static partial class Utils
{
public static Expression<Func<TItem, bool>> PropertyEquals<TItem, TValue>(string propertyPath, TValue value)
{
var source = Expression.Parameter(typeof(TItem), "source");
var propertyNames = propertyPath.Split('.');
var member = Expression.Property(source, propertyNames[0]);
for (int i = 1; i < propertyNames.Length; i++)
member = Expression.Property(member, propertyNames[i]);
Expression left = member, right = Expression.Constant(value, typeof(TValue));
if (left.Type != right.Type)
{
var nullableType = Nullable.GetUnderlyingType(left.Type);
if (nullableType != null)
right = Expression.Convert(right, left.Type);
else
left = Expression.Convert(left, right.Type);
}
var body = Expression.Equal(left, right);
var expr = Expression.Lambda<Func<TItem, bool>>(body, source);
return expr;
}
}
var predicate = Utils.PropertyEquals<Car, int>("Engine.HorsePower", 400);
bool result = predicate.Compile().Invoke(myCar);
List<Car> cars = new List<Car> { myCar };
var cars400 = cars.WherePropertyEquals("Engine.HorsePower", 400).ToList();
List cars=新列表{myCar};
var cars400=汽车。WherePropertyEquals(“发动机。马力”,400)。ToList();
有趣!然而,它需要动态地创建我的表达式,因为我不知道我的列表是由什么组成的,它是一个泛型。你能用我的PropertyEquals方法帮助实现你的概念吗?C#中的A表示你知道类型。你想通过这份清单实现什么?