【问题标题】:Get some properties from an object and nested object从对象和嵌套对象中获取一些属性
【发布时间】:2015-04-09 09:45:09
【问题描述】:

我想返回一个对象 (ExpandoObject),其中仅包含该方法接收的字段和嵌套字段。

var fieldsToGet = new List<string> { "FirstName", "Id"};

当我这样做时:

.Select(x => Helpers.FilteringProperties(x, fieldsToGet))

我收到一个具有这两个值的对象,这很有效。 我收到一个带有FirstNameId 的对象

现在我想返回嵌套对象的一些属性:

var fieldsToGet = new List<string> { "FirstName", "Id", "Language.Name"};

我想收到这些属性: FirstNameIdLanguage.Name

下面的代码有效,但我希望保持足够通用并能够管理嵌套。

我怎样才能做到这个通用的、托管的嵌套对象?

谢谢,

当前代码:

public static object FilteringProperties(object employee, List<string> fields)
{
    if (!fields.Any())
        return employee;
    else
    {
        ExpandoObject result = new ExpandoObject();
        foreach (var field in fields)
        {
            var fieldValue = employee.GetType()
            .GetProperty(field, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance)
            .GetValue(employee, null);

            ((IDictionary<String, Object>)result).Add(field, fieldValue);
        }
        return result;
    }
}

示例类:

public class Employee
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public Language Language { get; set; }
    public int LanguageId { get; set; }
}

public class Language
{
    public int Id { get; set; }
    public string Code { get; set; }
    public string Name { get; set; }
}

【问题讨论】:

    标签: c# .net linq reflection lambda


    【解决方案1】:

    我想您可以对“.”字符进行拆分,获取具有该名称的属性,然后通过递归调用您自己的函数来获取其值。

    类似这样的东西(伪代码,可以好多了)

    if (field.Contains(".")) {
       var parts = field.Split('.');
       var fieldName = parts[0];
       List<string> toGet = new List<string>();
       toGet.Add(parts[1]); // this now contains everything after the "." 
    
       var fieldValue = employee.GetType()
            .GetProperty(fieldName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance)
            .GetValue(employee, null);
    
       ((IDictionary<String, Object>)result).Add(field, FilteringProperties(fieldValue, toGet)
    }
    

    【讨论】:

    • 您必须将.GetProperty(field, 更改为.GetProperty(fieldName, ,并将FilteringProperties(fieldValue, toGet) 更改为((IDictionary&lt;String, Object&gt;)result).Add(field, FilteringProperties(fieldValue, toGet)
    • 注意到了,Xanatos!谢谢,我已经更新了我的帖子。
    • 在我的例子中,嵌套对象是一层但可以更多。
    【解决方案2】:

    使用递归方法。我相信它可以改进。

    public static object FilteringProperties(object employee, List<string> fields)
    {
        if (!fields.Any())
            return employee;
        else
        {
            ExpandoObject result = new ExpandoObject();
            foreach (var field in fields)
            {
                object fieldValue = null;
    
                Regex regex = new Regex("(\\w+)\\.(\\w+)");
                Match match = regex.Match(field);
                if (match.Success)
                {
                    string className = match.Groups[1].Value;
                    string propertyName = match.Groups[2].Value;
    
                    var o = FilteringProperties(employee.GetType().GetProperty(className).GetValue(employee, null), new List<string>() {propertyName});
                    var entry = (IDictionary<string, object>) o;
                    fieldValue = entry[propertyName];
                }
    
                if(fieldValue == null)
                    fieldValue = employee.GetType()
                    .GetProperty(field, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance)
                    .GetValue(employee, null);
    
                ((IDictionary<String, Object>)result).Add(field, fieldValue);
            }
            return result;
        }
    }
    

    【讨论】:

      【解决方案3】:

      这样的事情似乎对我有用 -

      public static ExpandoObject CreateObject(object parent, List<string> fields)
          {
              var expando = new ExpandoObject();
              var ret = (IDictionary<string,object>)expando;
      
              foreach (var property in fields)
              {
                  //split to determine if we are a nested property.
                  List<string> properties = property.Split('.').ToList();
                  if (properties.Count() > 1)
                  {
                      //get our 'childs' children - ignoring the first item 
                      var grandChildren = properties.Skip(1);
      
                      //copy this child object and use it to pass back into this method recusivly - thus creating our nested structure
                      var child = parent.GetType().GetProperty(properties[0]).GetValue(parent, null);
                      //passing in the child object and then its children - which are grandchildren from our parent.
                      ret.Add(properties[0], CreateObject(child, grandChildren.ToList()));
                  }
                  else //no nested properties just assign the property 
                      ret.Add(property, parent.GetType().GetProperty(property).GetValue(parent));
              }
      
              return expando;
          }
      

      【讨论】:

        【解决方案4】:

        感谢 Marc - 这个网站的大师 - 我想出了以下方法:

        public static object GetFlattenPropertyValue(this object source, string flattenPropertyName) {
        
            var expression = source.GetType().CreatePropertyExpression(flattenPropertyName);
        
            if (expression != null) {
                var getter = expression.Compile();
                return getter.DynamicInvoke(source);
            }
        
            return null;
        }
        
        public static LambdaExpression CreatePropertyExpression(this Type type, string flattenPropertyName) {
        
            if (flattenPropertyName == null) {
                return null;
            }
        
            var param = Expression.Parameter(type, "x");
            Expression body = param;
            foreach (var member in flattenPropertyName.Split('.')) {
                body = Expression.PropertyOrField(body, member);
            }
        
            return Expression.Lambda(body, param);
        }
        

        【讨论】:

          猜你喜欢
          • 2018-02-06
          • 1970-01-01
          • 1970-01-01
          • 2013-10-11
          • 2019-08-25
          • 1970-01-01
          • 2011-09-17
          • 1970-01-01
          • 2018-07-31
          相关资源
          最近更新 更多