簡體   English   中英

使用反射獲取嵌套的 Object 屬性值

[英]Getting Nested Object Property Value Using Reflection

我有以下兩個課程:

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; }
}

我有一個員工 class 的實例,如下所示:

    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); 無法找到嵌套的 object 屬性值。 有沒有辦法來解決這個問題?

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 個嵌套級別的麻煩。

var address = GetPropertyValue(GetPropertyValue(emp1, "Address"), "AddressLine1");

對象員工沒有一個名為“Address.AddressLine1”的屬性,它有一個名為“Address”的屬性,它本身有一個名為“AddressLine1”的屬性。

這將適用於無限數量的嵌套屬性。

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");

我使用此方法從屬性(無限數量的嵌套屬性)中獲取值,如下所示:

“財產”

“街道地址”

“地址.國家.名稱”

    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

獲取 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]);
            }

另一個變種扔在那里。 Short & Sweet,支持任意深度的屬性,處理空值和無效屬性:

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]);
}

我為這個提議做了一個關於類型的擴展方法:

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));
    }
}

上面的修改版本以獲取多級嵌套屬性

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);
            }
        }

這將適用於 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);
}

我在靜態類中的結構類型有問題,所以我必須使用這個方法 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}")
                }
            }
        }

遞歸方法,在一行中......

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;
}

我發現 DevT 發布的代碼幾乎成功了,但是當涉及 collections 時失敗了,例如申請人.地址 [0].FirstLine,所以我添加了一些代碼來解決這個問題。 我相信其他人可以改進。

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
        {
            if (propName.Contains("["))
            {
                int iterator_start = propName.IndexOf('[');
                int iterator_end = propName.IndexOf(']');
                string iterator_value = propName.Substring(iterator_start + 1, iterator_end - iterator_start - 1);
                string string_to_remove = "[" + iterator_value + "]";
                int iterator_number = Convert.ToInt32(iterator_value);
                propName = propName.Replace(string_to_remove, "");

                var prop2 = src.GetType().GetProperty(propName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
                Type type = prop2.PropertyType;
                if (type.IsGenericType && type.GetGenericTypeDefinition()
                        == typeof(List<>))
                {
                    System.Collections.IList oTheList = (System.Collections.IList)prop2.GetValue(src, null);
                    return  oTheList[iterator_number];
                }
            }
           
            var prop = src.GetType().GetProperty(propName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
            return prop != null ? prop.GetValue(src, null) : null;
            
                
        }
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM