我希望根据嵌套属性创建一个Linq Where。
让我们说这是我的项目:
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
}
};
我在某处找到了这个代码,它允许创建Expression,
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 );
}
现在,我想要一个等效的,调用我的方法PropertyEquals
var engine = myCar.Select( c => c.Engine.HorsePower == 400 );
像
这样的东西var property = GetPropertyForDotSequence( typeof( Car ), "Engine.HorsePower" );
.Select( PropertyEquals<TEntity, int>( property , 400 ) );
我发现了一种允许基于点式格式(GetPropertyForDotSequence)查找属性的方法,该格式正常工作,但返回HorsePower属性信息,而不是Engine.HorsePower,因此我收到一条错误消息,说Car没有调用int32属性马力。
private PropertyInfo GetPropertyForDotSequence ( Type baseType, string propertyName ) {
var parts = propertyName.Split( '.' );
return ( parts.Length > 1 )
? GetPropertyForDotSequence( baseType.GetProperty( parts[ 0 ] ).PropertyType, parts.Skip( 1 ).Aggregate( ( a, i ) => a + "." + i ) )
: baseType.GetProperty( propertyName );
}
答案 0 :(得分:1)
为了实现您的目标,不是使用单独的帮助函数从属性路径中提取最后属性信息,然后将属性信息传递给您的函数,所有这些都应该在内部完成函数本身,即它应该接收包含类似
的属性路径的string
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);
如果与以下扩展方法结合使用,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());
}
}
所以你可以写这样的东西
List<Car> cars = new List<Car> { myCar };
var cars400 = cars.WherePropertyEquals("Engine.HorsePower", 400).ToList();
答案 1 :(得分:0)
您可以使用此方法从<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Exercitiul 1</title>
<link rel="stylesheet" type="text/css" href="css/normalize.css">
<script src="scripts/script.js" type="text/javascript"></script>
</head>
<body>
<form name="formular">
<table>
<tr>
<td>Ziua</td>
<td><input type="text" name="zi"></td>
</tr>
<tr>
<td>Luna</td>
<td><input type="text" name="luna"></td>
</tr>
<tr>
<td></td>
<td><input type="button" value="Determinare zodie" id="buton"></td>
</tr>
<tr>
<td>Zodia</td>
<td><input type="text" name="zodie"></td>
</tr>
</table>
</form>
</body>
</html>
获取property
值,其中嵌套属性名称为object
string
但这不是有效的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
}
};
的值设为
Engine.HorsePower
修改强>
对于var horsePower = (int)GetNestedPropertyValue(myCar, "Engine.HorsePower");
示例,如果您有Linq
这样的
List<Car>
您可以将var myCar2 = new Car()
{
Engine = new Engine()
{
HorsePower = 800
}
};
var cars = new List<Car> { myCar, myCar2 }; //myCar defined above
用作
Linq