【问题标题】:Getting Nested Object Property Value Using Reflection使用反射获取嵌套对象属性值
【发布时间】:2010-03-29 01:05:37
【问题描述】:

我有以下两个类:

public class Address
{
    public string AddressLine1 { get; set; }
    public string AddressLine2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string Zip { get; set; }
}

public class Employee
{
    public string FirstName { get; set; }
    public string MiddleName { get; set; }
    public string LastName { get; set; }
    public Address EmployeeAddress { get; set; }
}

我有一个员工类的实例如下:

    var emp1Address = new Address();
    emp1Address.AddressLine1 = "Microsoft Corporation";
    emp1Address.AddressLine2 = "One Microsoft Way";
    emp1Address.City = "Redmond";
    emp1Address.State = "WA";
    emp1Address.Zip = "98052-6399";

    var emp1 = new Employee();
    emp1.FirstName = "Bill";
    emp1.LastName = "Gates";
    emp1.EmployeeAddress = emp1Address;

我有一个根据属性名获取属性值的方法,如下:

public object GetPropertyValue(object obj ,string propertyName)
{
    var objType = obj.GetType();
    var prop = objType.GetProperty(propertyName);

    return prop.GetValue(obj, null);
}

上述方法适用于像GetPropertyValue(emp1, "FirstName") 这样的调用,但如果我尝试GetPropertyValue(emp1, "Address.AddressLine1") 它会抛出异常,因为objType.GetProperty(propertyName); 无法定位嵌套对象属性值。有没有办法解决这个问题?

【问题讨论】:

    标签: c# asp.net reflection


    【解决方案1】:
    public object GetPropertyValue(object obj, string propertyName)
    {
        foreach (var prop in propertyName.Split('.').Select(s => obj.GetType().GetProperty(s)))
           obj = prop.GetValue(obj, null);
    
        return obj;
    }
    

    谢谢,我来这里是为了寻找相同问题的答案。我最终修改了您的原始方法以支持嵌套属性。这应该比必须进行嵌套方法调用更健壮,因为嵌套方法调用最终可能会导致超过 2 个嵌套级别变得繁琐。

    【讨论】:

    • 这是对另一个答案的回应吗?
    • 同一个“obj”用于反射类型检索时如何工作?
    • @YeenFei 他更新了 foreach 中的 obj 值(请参阅下面的每个代码部分...)
    【解决方案2】:
    var address = GetPropertyValue(GetPropertyValue(emp1, "Address"), "AddressLine1");
    

    Object Employee 没有一个名为“Address.AddressLine1”的属性,它有一个名为“Address”的属性,它本身也有一个名为“AddressLine1”的属性。

    【讨论】:

      【解决方案3】:

      这适用于无限数量的嵌套属性。

      public object GetPropertyValue(object obj, string propertyName)
      {
          var _propertyNames = propertyName.Split('.');
      
          for (var i = 0; i < _propertyNames.Length; i++)
          {
              if (obj != null)
              {
                  var _propertyInfo = obj.GetType().GetProperty(_propertyNames[i]);
                  if (_propertyInfo != null)
                      obj = _propertyInfo.GetValue(obj);
                  else
                      obj = null;
              }
          }
      
          return obj;
      }
      

      用法:

      GetPropertyValue(_employee, "Firstname");
      GetPropertyValue(_employee, "Address.State");
      GetPropertyValue(_employee, "Address.Country.Name");
      

      【讨论】:

        【解决方案4】:

        我使用这种方法从属性(无限数量的嵌套属性)中获取值,如下所示:

        “财产”

        “地址.街道”

        “Address.Country.Name”

            public static object GetPropertyValue(object src, string propName)
            {
                if (src == null) throw new ArgumentException("Value cannot be null.", "src");
                if (propName == null) throw new ArgumentException("Value cannot be null.", "propName");
        
                if(propName.Contains("."))//complex type nested
                {
                    var temp = propName.Split(new char[] { '.' }, 2);
                    return GetPropertyValue(GetPropertyValue(src, temp[0]), temp[1]);
                }
                else
                {
                    var prop = src.GetType().GetProperty(propName);
                    return prop != null ? prop.GetValue(src, null) : null;
                }
            }
        

        这里是小提琴:https://dotnetfiddle.net/PvKRH0

        【讨论】:

          【解决方案5】:

          获取 Nest 属性,例如 Developer.Project.Name

          private static System.Reflection.PropertyInfo GetProperty(object t, string PropertName)
                      {
                          if (t.GetType().GetProperties().Count(p => p.Name == PropertName.Split('.')[0]) == 0)
                              throw new ArgumentNullException(string.Format("Property {0}, is not exists in object {1}", PropertName, t.ToString()));
                          if (PropertName.Split('.').Length == 1)
                              return t.GetType().GetProperty(PropertName);
                          else
                              return GetProperty(t.GetType().GetProperty(PropertName.Split('.')[0]).GetValue(t, null), PropertName.Split('.')[1]);
                      }
          

          【讨论】:

            【解决方案6】:

            还有另一种变体。短小精悍,支持任意深度的属性,处理空值和无效属性:

            public static object GetPropertyVal(this object obj, string name) {
                if (obj == null)
                    return null;
            
                var parts = name.Split(new[] { '.' }, 2);
                var prop = obj.GetType().GetProperty(parts[0]);
                if (prop == null)
                    throw new ArgumentException($"{parts[0]} is not a property of {obj.GetType().FullName}.");
            
                var val = prop.GetValue(obj);
                return (parts.Length == 1) ? val : val.GetPropertyVal(parts[1]);
            }
            

            【讨论】:

              【解决方案7】:

              我为这个提议做了一个类型的扩展方法:

              public static class TypeExtensions
              {
                  public static PropertyInfo GetSubProperty(this Type type, string treeProperty, object givenValue)
                  {
                      var properties = treeProperty.Split('.');
                      var value = givenValue;
              
                      foreach (var property in properties.Take(properties.Length - 1))
                      {
                          value = value.GetType().GetProperty(property).GetValue(value);
              
                          if (value == null)
                          {
                              return null;
                          }
                      }
              
                      return value.GetType().GetProperty(properties[properties.Length - 1]);
                  }
              
                  public static object GetSubPropertyValue(this Type type, string treeProperty, object givenValue)
                  {
                      var properties = treeProperty.Split('.');
                      return properties.Aggregate(givenValue, (current, property) => current.GetType().GetProperty(property).GetValue(current));
                  }
              }
              

              【讨论】:

                【解决方案8】:

                上面的修改版本,用于获取多级嵌套属性

                private static System.Reflection.PropertyInfo GetProperty(object t, string PropertName, out object Value)
                        {
                            Value = "";
                            var v = t.GetType().GetProperties();
                            if (t.GetType().GetProperties().Count(p => p.Name == PropertName.Split('.')[0]) == 0)
                                //throw new ArgumentNullException(string.Format("Property {0}, is not exists in object {1}", PropertName, t.ToString()));
                                return null;
                            if (PropertName.Split('.').Length == 1)
                            {
                                var Value1 = t.GetType().GetProperty(PropertName).GetValue(t, null);
                                Value = Value1;//.ToString();
                                return t.GetType().GetProperty(PropertName);
                            }
                            else
                            {
                                //return GetProperty(t.GetType().GetProperty(PropertName.Split('.')[0]).GetValue(t, null), PropertName.Split('.')[1], out Value);
                                return GetProperty(t.GetType().GetProperty(PropertName.Split('.')[0]).GetValue(t, null), PropertName.Substring(PropertName.IndexOf('.') + 1, PropertName.Length - PropertName.IndexOf('.') - 1), out Value);
                            }
                        }
                

                【讨论】:

                  【解决方案9】:

                  这适用于 1 级和 2 级对象属性,例如FirstnameAddress.AddressLine1

                  public object GetPropertyValue(object obj, string propertyName)
                  {
                      object targetObject = obj;
                      string targetPropertyName = propertyName;
                  
                      if (propertyName.Contains('.'))
                      {
                          string[] split = propertyName.Split('.');
                          targetObject = obj.GetType().GetProperty(split[0]).GetValue(obj, null);
                          targetPropertyName = split[1];
                      }
                  
                      return targetObject.GetType().GetProperty(targetPropertyName).GetValue(targetObject, null);
                  }
                  

                  【讨论】:

                    【解决方案10】:

                    我在静态类中的结构类型有问题,所以我必须使用这个方法GetNestedType,如果你知道属性名称,这是示例代码,如果你想getAll,你可以使用GetNestedTypes

                    此示例中的ExpandoObject 仅用于动态添加属性和值

                    private void ExtractValuesFromAppconstants(string keyName)
                            {
                                Type type = typeof(YourClass);
                                var examination = type.GetNestedType(keyName);
                                if (examination != null)
                                {    
                                    var innerTypes = examination.GetNestedTypes();
                                    foreach (var innerType in innerTypes)
                                    {
                                        Console.Writeline($"{innerType.Name}")
                                    }
                                }
                            }
                    

                    【讨论】:

                      【解决方案11】:

                      递归方法,一行一行……

                      object GetPropertyValue(object obj, string propertyName)
                      {
                          return propertyName.Contains(".") ? GetPropertyValue(obj.GetType().GetProperty(propertyName.Split(".").First()).GetValue(obj), string.Join(".", propertyName.Split(".").Skip(1))) : obj != null ? obj.GetType().GetProperty(propertyName).GetValue(obj) : null;
                      }
                      

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2011-02-24
                        • 2010-12-29
                        • 1970-01-01
                        • 1970-01-01
                        相关资源
                        最近更新 更多