Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 具有嵌套属性值反射的LINQ_C#_.net_Linq_Reflection_Propertyinfo - Fatal编程技术网

C# 具有嵌套属性值反射的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 } }; 我使用在某处找到

我希望创建一个基于嵌套属性的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
    }
};
我使用在某处找到的代码,它允许创建表达式

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表示你知道类型。你想通过这份清单实现什么?