使用嵌套属性动态生成 LINQ 选择

目前我们有一个包可以从字符串中的字段动态生成 linq 选择。它适用于平面属性,但它不是设计用于嵌套字段,如 someObj.NestedObj.SomeField。


我们当前的代码在服务方法中的工作方式如下:


_context.Shipments

    .Where(s => s.Id == request.Id) // it does not matter just an example

    .Select(request.Fields)

    .ToPage(request); // ToPage extension comes from a nuget package

请求对象的参数“字段”只是一个以逗号分隔的字符串,包括 Shipment 对象的属性。


我对 Shipment 进行了一些重构,我将一些字段分组到一个名为 Address 的新类中,并将其添加到 Shipment 中,如下所示:


// before refactoring

class Shipment {

    // other fields...

    public string SenderAddress;

    public string SenderCityName;

    public string SenderCityId;


    public string RecipientAddress;

    public string CityName;

    public string CityId;

}


// after refactoring

class Shipment {

   // other fields...

   public Address Sender;

   public Address Recipient;

}


class Address {

    public string AddressText;

    public string CityName;

    public string CityId;

}

为了当前的数据库映射,我添加了相应的映射:


public class ShipmentMap : DataEntityTypeConfiguration<Shipment>

    {

        public ShipmentMap()

        {

            ToTable("Shipments");

            // other property mappings

            Property(s => s.Recipient.AddressText).HasMaxLength(1100).HasColumnName("RecipientAddress");

            Property(s => s.Recipient.CityName).HasMaxLength(100).HasColumnName("CityName");

            Property(s => s.Recipient.CityId).IsOptional().HasColumnName("CityId");


            Property(s => s.Sender.AddressText).HasMaxLength(1100).HasColumnName("SenderAddress");

            Property(s => s.Sender.CityName).HasMaxLength(100).HasColumnName("SenderCityName");

            Property(s => s.Sender.CityId).IsOptional().HasColumnName("SenderCityId");

        }

    }

DataEntityTypeConfiguration 来自 nuget 包:


  public abstract class DataEntityTypeConfiguration<T> : EntityTypeConfiguration<T> where T : class

  {

    protected virtual void PostInitialize();

  }

所以,我的问题是 select(fields) 在 fields = "Recipient.CityId" 时不起作用。


如何动态生成用于选择嵌套字段的 linq?


浮云间
浏览 220回答 3
3回答

拉风的咖菲猫

很高兴您找到了解决您的特定问题的方法。这是一个更通用的解决方案,一旦原始属性名称和类型匹配(例如Entity->Dto等),以及多级嵌套,它就会处理不同的源和目标类型:public static Expression<Func<TSource, TTarget>> BuildSelector<TSource, TTarget>(string members) =>&nbsp; &nbsp; BuildSelector<TSource, TTarget>(members.Split(',').Select(m => m.Trim()));public static Expression<Func<TSource, TTarget>> BuildSelector<TSource, TTarget>(IEnumerable<string> members){&nbsp; &nbsp; var parameter = Expression.Parameter(typeof(TSource), "e");&nbsp; &nbsp; var body = NewObject(typeof(TTarget), parameter, members.Select(m => m.Split('.')));&nbsp; &nbsp; return Expression.Lambda<Func<TSource, TTarget>>(body, parameter);}static Expression NewObject(Type targetType, Expression source, IEnumerable<string[]> memberPaths, int depth = 0){&nbsp; &nbsp; var bindings = new List<MemberBinding>();&nbsp; &nbsp; var target = Expression.Constant(null, targetType);&nbsp; &nbsp; foreach (var memberGroup in memberPaths.GroupBy(path => path[depth]))&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var memberName = memberGroup.Key;&nbsp; &nbsp; &nbsp; &nbsp; var targetMember = Expression.PropertyOrField(target, memberName);&nbsp; &nbsp; &nbsp; &nbsp; var sourceMember = Expression.PropertyOrField(source, memberName);&nbsp; &nbsp; &nbsp; &nbsp; var childMembers = memberGroup.Where(path => depth + 1 < path.Length);&nbsp; &nbsp; &nbsp; &nbsp; var targetValue = !childMembers.Any() ? sourceMember :&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; NewObject(targetMember.Type, sourceMember, childMembers, depth + 1);&nbsp; &nbsp; &nbsp; &nbsp; bindings.Add(Expression.Bind(targetMember.Member, targetValue));&nbsp; &nbsp; }&nbsp; &nbsp; return Expression.MemberInit(Expression.New(targetType), bindings);}前两种方法只是公开暴露的高级助手。实际工作是通过私有递归NewObject方法完成的。它对当前级别的属性进行分组,并且对于每个分组,要么创建简单的分配,就像PropertyN = source.Property1.Property2...PropertyN它是最后一个级别一样,要么递归地PropertyN = new TypeN { … }否则。与您的示例中的表达式匹配的示例用法:var test = BuildSelector<Shipment, Shipment>(&nbsp; &nbsp; "Recipient.CityName, Sender.CityId, Sender.CityName, ParcelUniqueId");只需Compile在需要时调用Func。

素胚勾勒不出你

最后我找到了解决方案。它为两级嵌套属性(如 Shipment.Sender.CityName)生成正确的 lambda。所以任何需要同样东西的人都可以使用它。我希望它有帮助。/* this comes from request*&nbsp; request.Fields = "Sender.CityId,Sender.CityName,Recipient.CityName,parcelUniqueId"*/// in the service methodvar shipmentList = _context.Shipments.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .OrderByDescending(s => s.Id)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .Skip((request.Page -1) * request.PageSize)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .Take(request.PageSize)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .Select(new SelectLambdaBuilder<Shipment>().CreateNewStatement(request.Fields))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .ToList();public class SelectLambdaBuilder<T>{&nbsp; &nbsp; // as a performence consideration I cached already computed type-properties&nbsp; &nbsp; private static Dictionary<Type, PropertyInfo[]> _typePropertyInfoMappings = new Dictionary<Type, PropertyInfo[]>();&nbsp; &nbsp; private readonly Type _typeOfBaseClass = typeof(T);&nbsp; &nbsp; private Dictionary<string, List<string>> GetFieldMapping(string fields)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var selectedFieldsMap = new Dictionary<string, List<string>>();&nbsp; &nbsp; &nbsp; &nbsp; foreach (var s in fields.Split(','))&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var nestedFields = s.Split('.').Select(f => f.Trim()).ToArray();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var nestedValue = nestedFields.Length > 1 ? nestedFields[1] : null;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (selectedFieldsMap.Keys.Any(key => key == nestedFields[0]))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; selectedFieldsMap[nestedFields[0]].Add(nestedValue);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; selectedFieldsMap.Add(nestedFields[0], new List<string> { nestedValue });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return selectedFieldsMap;&nbsp; &nbsp; }&nbsp; &nbsp; public Func<T, T> CreateNewStatement(string fields)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; ParameterExpression xParameter = Expression.Parameter(_typeOfBaseClass, "s");&nbsp; &nbsp; &nbsp; &nbsp; NewExpression xNew = Expression.New(_typeOfBaseClass);&nbsp; &nbsp; &nbsp; &nbsp; var selectFields = GetFieldMapping(fields);&nbsp; &nbsp; &nbsp; &nbsp; var shpNestedPropertyBindings = new List<MemberAssignment>();&nbsp; &nbsp; &nbsp; &nbsp; foreach (var keyValuePair in selectFields)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PropertyInfo[] propertyInfos;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (!_typePropertyInfoMappings.TryGetValue(_typeOfBaseClass, out propertyInfos))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var properties = _typeOfBaseClass.GetProperties();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; propertyInfos = properties;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _typePropertyInfoMappings.Add(_typeOfBaseClass, properties);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var propertyType = propertyInfos&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .FirstOrDefault(p => p.Name.ToLowerInvariant().Equals(keyValuePair.Key.ToLowerInvariant()))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .PropertyType;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (propertyType.IsClass)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PropertyInfo objClassPropInfo = _typeOfBaseClass.GetProperty(keyValuePair.Key);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MemberExpression objNestedMemberExpression = Expression.Property(xParameter, objClassPropInfo);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; NewExpression innerObjNew = Expression.New(propertyType);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var nestedBindings = keyValuePair.Value.Select(v =>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PropertyInfo nestedObjPropInfo = propertyType.GetProperty(v);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MemberExpression nestedOrigin2 = Expression.Property(objNestedMemberExpression, nestedObjPropInfo);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var binding2 = Expression.Bind(nestedObjPropInfo, nestedOrigin2);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return binding2;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MemberInitExpression nestedInit = Expression.MemberInit(innerObjNew, nestedBindings);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; shpNestedPropertyBindings.Add(Expression.Bind(objClassPropInfo, nestedInit));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Expression mbr = xParameter;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mbr = Expression.PropertyOrField(mbr, keyValuePair.Key);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PropertyInfo mi = _typeOfBaseClass.GetProperty( ((MemberExpression)mbr).Member.Name );&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var xOriginal = Expression.Property(xParameter, mi);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; shpNestedPropertyBindings.Add(Expression.Bind(mi, xOriginal));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; var xInit = Expression.MemberInit(xNew, shpNestedPropertyBindings);&nbsp; &nbsp; &nbsp; &nbsp; var lambda = Expression.Lambda<Func<T,T>>( xInit, xParameter );&nbsp; &nbsp; &nbsp; &nbsp; return lambda.Compile();&nbsp; &nbsp; }它编译 lambda 如下:s => new Shipment {&nbsp; &nbsp; Recipient = new Address {&nbsp; &nbsp; &nbsp; &nbsp; CityName = s.Recipient.CityName&nbsp; &nbsp; },&nbsp; &nbsp; Sender = new Address {&nbsp; &nbsp; &nbsp; &nbsp; CityId = s.Sender.CityId,&nbsp; &nbsp; &nbsp; &nbsp; CityName = s.Sender.CityName&nbsp; &nbsp; },&nbsp; &nbsp; ParcelUniqueId = s.ParcelUniqueId}我分享了 debug 的一些截图:

汪汪一只猫

最后我找到了解决方案。它为两级嵌套属性(如 Shipment.Sender.CityName)生成正确的 lambda。所以任何需要同样东西的人都可以使用它。我希望它有帮助。/* this comes from request*&nbsp; request.Fields = "Sender.CityId,Sender.CityName,Recipient.CityName,parcelUniqueId"*/// in the service methodvar shipmentList = _context.Shipments.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .OrderByDescending(s => s.Id)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .Skip((request.Page -1) * request.PageSize)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .Take(request.PageSize)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .Select(new SelectLambdaBuilder<Shipment>().CreateNewStatement(request.Fields))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .ToList();public class SelectLambdaBuilder<T>{&nbsp; &nbsp; // as a performence consideration I cached already computed type-properties&nbsp; &nbsp; private static Dictionary<Type, PropertyInfo[]> _typePropertyInfoMappings = new Dictionary<Type, PropertyInfo[]>();&nbsp; &nbsp; private readonly Type _typeOfBaseClass = typeof(T);&nbsp; &nbsp; private Dictionary<string, List<string>> GetFieldMapping(string fields)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var selectedFieldsMap = new Dictionary<string, List<string>>();&nbsp; &nbsp; &nbsp; &nbsp; foreach (var s in fields.Split(','))&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var nestedFields = s.Split('.').Select(f => f.Trim()).ToArray();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var nestedValue = nestedFields.Length > 1 ? nestedFields[1] : null;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (selectedFieldsMap.Keys.Any(key => key == nestedFields[0]))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; selectedFieldsMap[nestedFields[0]].Add(nestedValue);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; selectedFieldsMap.Add(nestedFields[0], new List<string> { nestedValue });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return selectedFieldsMap;&nbsp; &nbsp; }&nbsp; &nbsp; public Func<T, T> CreateNewStatement(string fields)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; ParameterExpression xParameter = Expression.Parameter(_typeOfBaseClass, "s");&nbsp; &nbsp; &nbsp; &nbsp; NewExpression xNew = Expression.New(_typeOfBaseClass);&nbsp; &nbsp; &nbsp; &nbsp; var selectFields = GetFieldMapping(fields);&nbsp; &nbsp; &nbsp; &nbsp; var shpNestedPropertyBindings = new List<MemberAssignment>();&nbsp; &nbsp; &nbsp; &nbsp; foreach (var keyValuePair in selectFields)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PropertyInfo[] propertyInfos;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (!_typePropertyInfoMappings.TryGetValue(_typeOfBaseClass, out propertyInfos))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var properties = _typeOfBaseClass.GetProperties();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; propertyInfos = properties;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _typePropertyInfoMappings.Add(_typeOfBaseClass, properties);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var propertyType = propertyInfos&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .FirstOrDefault(p => p.Name.ToLowerInvariant().Equals(keyValuePair.Key.ToLowerInvariant()))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .PropertyType;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (propertyType.IsClass)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PropertyInfo objClassPropInfo = _typeOfBaseClass.GetProperty(keyValuePair.Key);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MemberExpression objNestedMemberExpression = Expression.Property(xParameter, objClassPropInfo);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; NewExpression innerObjNew = Expression.New(propertyType);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var nestedBindings = keyValuePair.Value.Select(v =>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PropertyInfo nestedObjPropInfo = propertyType.GetProperty(v);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MemberExpression nestedOrigin2 = Expression.Property(objNestedMemberExpression, nestedObjPropInfo);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var binding2 = Expression.Bind(nestedObjPropInfo, nestedOrigin2);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return binding2;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MemberInitExpression nestedInit = Expression.MemberInit(innerObjNew, nestedBindings);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; shpNestedPropertyBindings.Add(Expression.Bind(objClassPropInfo, nestedInit));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Expression mbr = xParameter;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mbr = Expression.PropertyOrField(mbr, keyValuePair.Key);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PropertyInfo mi = _typeOfBaseClass.GetProperty( ((MemberExpression)mbr).Member.Name );&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var xOriginal = Expression.Property(xParameter, mi);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; shpNestedPropertyBindings.Add(Expression.Bind(mi, xOriginal));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; var xInit = Expression.MemberInit(xNew, shpNestedPropertyBindings);&nbsp; &nbsp; &nbsp; &nbsp; var lambda = Expression.Lambda<Func<T,T>>( xInit, xParameter );&nbsp; &nbsp; &nbsp; &nbsp; return lambda.Compile();&nbsp; &nbsp; }它编译 lambda 如下:s => new Shipment {&nbsp; &nbsp; Recipient = new Address {&nbsp; &nbsp; &nbsp; &nbsp; CityName = s.Recipient.CityName&nbsp; &nbsp; },&nbsp; &nbsp; Sender = new Address {&nbsp; &nbsp; &nbsp; &nbsp; CityId = s.Sender.CityId,&nbsp; &nbsp; &nbsp; &nbsp; CityName = s.Sender.CityName&nbsp; &nbsp; },&nbsp; &nbsp; ParcelUniqueId = s.ParcelUniqueId}我分享了 debug 的一些截图:我相信你的问题出在这段代码中:string[] nestedProps = o.Split('.');Expression mbr = xParameter;foreach (var prop in nestedProps)&nbsp; &nbsp; mbr = Expression.PropertyOrField(mbr, prop);// property "Field1"PropertyInfo mi = typeof( Shipment ).GetProperty( ((MemberExpression)mbr).Member.Name );该foreach循环被重复地将值分配给mbr,然后覆盖它,这意味着它的最终值将是表达等效过去值的nestedProps。假设输入字符串是"Recipient.CityId",mbr将是 的表达式CityId。然后,您尝试GetProperty在Shipment类型上查找名称为 的属性,该属性CityId当然不存在(CityId作为 的属性Address)。不过,我不确定要解决什么问题,因为我不确定您最终想要什么。
打开App,查看更多内容
随时随地看视频慕课网APP