在 C# 中使用反射获取嵌套对象的属性

发布于 2024-08-15 10:14:59 字数 1217 浏览 6 评论 0原文

给定以下对象:

public class Customer {
    public String Name { get; set; }
    public String Address { get; set; }
}

public class Invoice {
    public String ID { get; set; }
    public DateTime Date { get; set; }
    public Customer BillTo { get; set; }
}

我想使用反射来遍历 Invoice 来获取 CustomerName 属性。这就是我所追求的,假设此代码可以工作:

Invoice inv = GetDesiredInvoice();  // magic method to get an invoice
PropertyInfo info = inv.GetType().GetProperty("BillTo.Address");
Object val = info.GetValue(inv, null);

当然,这会失败,因为“BillTo.Address”不是 Invoice 类的有效属性。

因此,我尝试编写一种方法来将字符串分割成句点上的片段,并遍历对象寻找我感兴趣的最终值。它工作正常,但我对此并不完全满意:

public Object GetPropValue(String name, Object obj) {
    foreach (String part in name.Split('.')) {
        if (obj == null) { return null; }

        Type type = obj.GetType();
        PropertyInfo info = type.GetProperty(part);
        if (info == null) { return null; }

        obj = info.GetValue(obj, null);
    }
    return obj;
}

关于如何改进这个方法,或者有更好的方法来解决这个问题?

编辑发布后,我看到了一些相关的帖子......但是,似乎没有专门解决这个问题的答案。另外,我仍然希望获得有关我的实施的反馈。

Given the following objects:

public class Customer {
    public String Name { get; set; }
    public String Address { get; set; }
}

public class Invoice {
    public String ID { get; set; }
    public DateTime Date { get; set; }
    public Customer BillTo { get; set; }
}

I'd like to use reflection to go through the Invoice to get the Name property of a Customer. Here's what I'm after, assuming this code would work:

Invoice inv = GetDesiredInvoice();  // magic method to get an invoice
PropertyInfo info = inv.GetType().GetProperty("BillTo.Address");
Object val = info.GetValue(inv, null);

Of course, this fails since "BillTo.Address" is not a valid property of the Invoice class.

So, I tried writing a method to split the string into pieces on the period, and walk the objects looking for the final value I was interested in. It works okay, but I'm not entirely comfortable with it:

public Object GetPropValue(String name, Object obj) {
    foreach (String part in name.Split('.')) {
        if (obj == null) { return null; }

        Type type = obj.GetType();
        PropertyInfo info = type.GetProperty(part);
        if (info == null) { return null; }

        obj = info.GetValue(obj, null);
    }
    return obj;
}

Any ideas on how to improve this method, or a better way to solve this problem?

EDIT after posting, I saw a few related posts... There doesn't seem to be an answer that specifically addresses this question, however. Also, I'd still like the feedback on my implementation.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

过潦 2024-08-22 10:14:59

我使用以下方法从(嵌套类)属性中获取值,例如

"Property"

"Address.Street"

"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

I use following method to get the values from (nested classes) properties like

"Property"

"Address.Street"

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

Here is the Fiddle: https://dotnetfiddle.net/PvKRH0

愿与i 2024-08-22 10:14:59

我知道我参加聚会有点晚了,正如其他人所说,你的实现很好
...用于简单用例
不过,我开发了一个库,可以准确解决该用例,Pather.CSharp
它也可以作为 Nuget 包 提供。

它的主类是 Resolver 及其 Resolve 方法。
您向其传递一个对象和属性路径,它将返回所需值

Invoice inv = GetDesiredInvoice();  // magic method to get an invoice
var resolver = new Resolver();
object result = resolver.Resolve(inv, "BillTo.Address");

但它还可以解析更复杂的属性路径,包括数组和字典访问。
因此,例如,如果您的客户多个地址

public class Customer {
    public String Name { get; set; }
    public IEnumerable<String> Addresses { get; set; }
}

您可以使用Addresses[1]访问第二个地址。

Invoice inv = GetDesiredInvoice();  // magic method to get an invoice
var resolver = new Resolver();
object result = resolver.Resolve(inv, "BillTo.Addresses[1]");

I know I'm a bit late to the party, and as others said, your implementation is fine
...for simple use cases.
However, I've developed a library that solves exactly that use case, Pather.CSharp.
It is also available as Nuget Package.

Its main class is Resolver with its Resolve method.
You pass it an object and the property path, and it will return the desired value.

Invoice inv = GetDesiredInvoice();  // magic method to get an invoice
var resolver = new Resolver();
object result = resolver.Resolve(inv, "BillTo.Address");

But it can also resolve more complex property paths, including array and dictionary access.
So, for example, if your Customer had multiple addresses

public class Customer {
    public String Name { get; set; }
    public IEnumerable<String> Addresses { get; set; }
}

you could access the second one using Addresses[1].

Invoice inv = GetDesiredInvoice();  // magic method to get an invoice
var resolver = new Resolver();
object result = resolver.Resolve(inv, "BillTo.Addresses[1]");
吾家有女初长成 2024-08-22 10:14:59

其实我觉得你的逻辑很好。就我个人而言,我可能会对其进行更改,以便将对象作为第一个参数传递(这与 PropertyInfo.GetValue 更一致,因此不那么令人惊讶)。

我也可能将其称为更像 GetNestedPropertyValue 的名称,以使其明显地在属性堆栈中进行搜索。

I actually think your logic is fine. Personally, I would probably change it around so you pass the object as the first parameter (which is more inline with PropertyInfo.GetValue, so less surprising).

I also would probably call it something more like GetNestedPropertyValue, to make it obvious that it searches down the property stack.

残花月 2024-08-22 10:14:59

您必须访问需要使用反射的实际对象。这就是我的意思:

而不是这样:

Invoice inv = GetDesiredInvoice();  // magic method to get an invoice
PropertyInfo info = inv.GetType().GetProperty("BillTo.Address");
Object val = info.GetValue(inv, null);

这样做(根据评论编辑):

Invoice inv = GetDesiredInvoice();  // magic method to get an invoice
PropertyInfo info = inv.GetType().GetProperty("BillTo");
Customer cust = (Customer)info.GetValue(inv, null);

PropertyInfo info2 = cust.GetType().GetProperty("Address");
Object val = info2.GetValue(cust, null);

查看这篇文章以获取更多信息:
使用反射设置 a 的属性对象的属性

You have to access the ACTUAL object that you need to use reflection on. Here is what I mean:

Instead of this:

Invoice inv = GetDesiredInvoice();  // magic method to get an invoice
PropertyInfo info = inv.GetType().GetProperty("BillTo.Address");
Object val = info.GetValue(inv, null);

Do this (edited based on comment):

Invoice inv = GetDesiredInvoice();  // magic method to get an invoice
PropertyInfo info = inv.GetType().GetProperty("BillTo");
Customer cust = (Customer)info.GetValue(inv, null);

PropertyInfo info2 = cust.GetType().GetProperty("Address");
Object val = info2.GetValue(cust, null);

Look at this post for more information:
Using reflection to set a property of a property of an object

掩耳倾听 2024-08-22 10:14:59

为了避免听起来太晚,我想添加我的解决方案:
在这种情况下肯定使用递归

public static Object GetPropValue(String name, object obj, Type type)
    {
        var parts = name.Split('.').ToList();
        var currentPart = parts[0];
        PropertyInfo info = type.GetProperty(currentPart);
        if (info == null) { return null; }
        if (name.IndexOf(".") > -1)
        {
            parts.Remove(currentPart);
            return GetPropValue(String.Join(".", parts), info.GetValue(obj, null), info.PropertyType);
        } else
        {
            return info.GetValue(obj, null).ToString();
        }
    }

In hopes of not sounding too late to the party, I would like to add my solution:
Definitely use recursion in this situation

public static Object GetPropValue(String name, object obj, Type type)
    {
        var parts = name.Split('.').ToList();
        var currentPart = parts[0];
        PropertyInfo info = type.GetProperty(currentPart);
        if (info == null) { return null; }
        if (name.IndexOf(".") > -1)
        {
            parts.Remove(currentPart);
            return GetPropValue(String.Join(".", parts), info.GetValue(obj, null), info.PropertyType);
        } else
        {
            return info.GetValue(obj, null).ToString();
        }
    }
菩提树下叶撕阳。 2024-08-22 10:14:59

您没有解释“不适”的根源,但您的代码对我来说基本上看起来不错。

我唯一质疑的是错误处理。如果代码尝试遍历 null 引用或属性名称不存在,则返回 null。这隐藏了错误:很难知道它是否返回 null,因为没有 BillTo 客户,或者因为您拼错了“BilTo.Address”...或者因为有 BillTo 客户,并且其地址为 null!在这些情况下,我会让方法崩溃并烧毁——只是让异常逃脱(或者可能将其包装在一个更友好的异常中)。

You don't explain the source of your "discomfort," but your code basically looks sound to me.

The only thing I'd question is the error handling. You return null if the code tries to traverse through a null reference or if the property name doesn't exist. This hides errors: it's hard to know whether it returned null because there's no BillTo customer, or because you misspelled it "BilTo.Address"... or because there is a BillTo customer, and its Address is null! I'd let the method crash and burn in these cases -- just let the exception escape (or maybe wrap it in a friendlier one).

攒一口袋星星 2024-08-22 10:14:59

这是另一个实现,如果嵌套属性是枚举器,它将跳过并继续深入。字符串类型的属性不受枚举检查的影响。

public static class ReflectionMethods
{
    public static bool IsNonStringEnumerable(this PropertyInfo pi)
    {
        return pi != null && pi.PropertyType.IsNonStringEnumerable();
    }

    public static bool IsNonStringEnumerable(this object instance)
    {
        return instance != null && instance.GetType().IsNonStringEnumerable();
    }

    public static bool IsNonStringEnumerable(this Type type)
    {
        if (type == null || type == typeof(string))
            return false;
        return typeof(IEnumerable).IsAssignableFrom(type);
    }

    public static Object GetPropValue(String name, Object obj)
    {
        foreach (String part in name.Split('.'))
        {
            if (obj == null) { return null; }
            if (obj.IsNonStringEnumerable())
            {
                var toEnumerable = (IEnumerable)obj;
                var iterator = toEnumerable.GetEnumerator();
                if (!iterator.MoveNext())
                {
                    return null;
                }
                obj = iterator.Current;
            }
            Type type = obj.GetType();
            PropertyInfo info = type.GetProperty(part);
            if (info == null) { return null; }

            obj = info.GetValue(obj, null);
        }
        return obj;
    }
}

基于这个问题和

如何知道 PropertyInfo 是否是集合
作者:贝里尔


我在 MVC 项目中使用它来动态排序我的数据,只需传递要排序的属性
示例:

result = result.OrderBy((s) =>
                {
                    return ReflectionMethods.GetPropValue("BookingItems.EventId", s);
                }).ToList();

其中 BookingItems 是对象列表。

Here is another implementation that will skip a nested property if it is an enumerator and continue deeper. Properties of type string are not affected by the Enumeration Check.

public static class ReflectionMethods
{
    public static bool IsNonStringEnumerable(this PropertyInfo pi)
    {
        return pi != null && pi.PropertyType.IsNonStringEnumerable();
    }

    public static bool IsNonStringEnumerable(this object instance)
    {
        return instance != null && instance.GetType().IsNonStringEnumerable();
    }

    public static bool IsNonStringEnumerable(this Type type)
    {
        if (type == null || type == typeof(string))
            return false;
        return typeof(IEnumerable).IsAssignableFrom(type);
    }

    public static Object GetPropValue(String name, Object obj)
    {
        foreach (String part in name.Split('.'))
        {
            if (obj == null) { return null; }
            if (obj.IsNonStringEnumerable())
            {
                var toEnumerable = (IEnumerable)obj;
                var iterator = toEnumerable.GetEnumerator();
                if (!iterator.MoveNext())
                {
                    return null;
                }
                obj = iterator.Current;
            }
            Type type = obj.GetType();
            PropertyInfo info = type.GetProperty(part);
            if (info == null) { return null; }

            obj = info.GetValue(obj, null);
        }
        return obj;
    }
}

based on this question and on

How to know if a PropertyInfo is a collection
by Berryl

I use this in a MVC project to dynamically Order my data by simply passing the Property to sort by
Example:

result = result.OrderBy((s) =>
                {
                    return ReflectionMethods.GetPropValue("BookingItems.EventId", s);
                }).ToList();

where BookingItems is a list of objects.

巴黎盛开的樱花 2024-08-22 10:14:59

<前><代码>>获取 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]);
            }
> Get Nest properties e.g., 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]);
            }
浅唱々樱花落 2024-08-22 10:14:59
   if (info == null) { /* throw exception instead*/ } 

如果他们请求一个不存在的属性,我实际上会抛出异常。按照您的编码方式,如果我调用 GetPropValue 并且它返回 null,我不知道这是否意味着该属性不存在,或者该属性确实存在但其值为 null。

   if (info == null) { /* throw exception instead*/ } 

I would actually throw an exception if they request a property that doesn't exist. The way you have it coded, if I call GetPropValue and it returns null, I don't know if that means the property didn't exist, or the property did exist but it's value was null.

风尘浪孓 2024-08-22 10:14:59
    public static string GetObjectPropertyValue(object obj, string propertyName)
    {
        bool propertyHasDot = propertyName.IndexOf(".") > -1;
        string firstPartBeforeDot;
        string nextParts = "";

        if (!propertyHasDot)
            firstPartBeforeDot = propertyName.ToLower();
        else
        {
            firstPartBeforeDot = propertyName.Substring(0, propertyName.IndexOf(".")).ToLower();
            nextParts = propertyName.Substring(propertyName.IndexOf(".") + 1);
        }

        foreach (var property in obj.GetType().GetProperties())
            if (property.Name.ToLower() == firstPartBeforeDot)
                if (!propertyHasDot)
                    if (property.GetValue(obj, null) != null)
                        return property.GetValue(obj, null).ToString();
                    else
                        return DefaultValue(property.GetValue(obj, null), propertyName).ToString();
                else
                    return GetObjectPropertyValue(property.GetValue(obj, null), nextParts);
        throw new Exception("Property '" + propertyName.ToString() + "' not found in object '" + obj.ToString() + "'");
    }
    public static string GetObjectPropertyValue(object obj, string propertyName)
    {
        bool propertyHasDot = propertyName.IndexOf(".") > -1;
        string firstPartBeforeDot;
        string nextParts = "";

        if (!propertyHasDot)
            firstPartBeforeDot = propertyName.ToLower();
        else
        {
            firstPartBeforeDot = propertyName.Substring(0, propertyName.IndexOf(".")).ToLower();
            nextParts = propertyName.Substring(propertyName.IndexOf(".") + 1);
        }

        foreach (var property in obj.GetType().GetProperties())
            if (property.Name.ToLower() == firstPartBeforeDot)
                if (!propertyHasDot)
                    if (property.GetValue(obj, null) != null)
                        return property.GetValue(obj, null).ToString();
                    else
                        return DefaultValue(property.GetValue(obj, null), propertyName).ToString();
                else
                    return GetObjectPropertyValue(property.GetValue(obj, null), nextParts);
        throw new Exception("Property '" + propertyName.ToString() + "' not found in object '" + obj.ToString() + "'");
    }
泡沫很甜 2024-08-22 10:14:59

我想分享我的解决方案,尽管可能为时已晚。该解决方案主要是检查嵌套属性是否存在。但如果需要,可以轻松调整它以返回属性值。

private static PropertyInfo _GetPropertyInfo(Type type, string propertyName)
        {
            //***
            //*** Check if the property name is a complex nested type
            //***
            if (propertyName.Contains("."))
            {
                //***
                //*** Get the first property name of the complex type
                //***
                var tempPropertyName = propertyName.Split(".", 2);
                //***
                //*** Check if the property exists in the type
                //***
                var prop = _GetPropertyInfo(type, tempPropertyName[0]);
                if (prop != null)
                {
                    //***
                    //*** Drill down to check if the nested property exists in the complex type
                    //***
                    return _GetPropertyInfo(prop.PropertyType, tempPropertyName[1]);
                }
                else
                {
                    return null;
                }
            }
            else
            {
                return type.GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
            }
        }

我必须参考一些帖子才能提出这个解决方案。我认为这适用于多个嵌套属性类型。

I wanted to share my solution although it may be too late. This solution is primarily to check if the nested property exists. But it can be easily tweaked to return the property value if needed.

private static PropertyInfo _GetPropertyInfo(Type type, string propertyName)
        {
            //***
            //*** Check if the property name is a complex nested type
            //***
            if (propertyName.Contains("."))
            {
                //***
                //*** Get the first property name of the complex type
                //***
                var tempPropertyName = propertyName.Split(".", 2);
                //***
                //*** Check if the property exists in the type
                //***
                var prop = _GetPropertyInfo(type, tempPropertyName[0]);
                if (prop != null)
                {
                    //***
                    //*** Drill down to check if the nested property exists in the complex type
                    //***
                    return _GetPropertyInfo(prop.PropertyType, tempPropertyName[1]);
                }
                else
                {
                    return null;
                }
            }
            else
            {
                return type.GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
            }
        }

I had to refer to few posts to come up with this solution. I think this will work for multiple nested property types.

左秋 2024-08-22 10:14:59

当我需要解决同样的问题时,我的互联网连接中断了,所以我不得不“重新发明轮子”:

static object GetPropertyValue(Object fromObject, string propertyName)
{
    Type objectType = fromObject.GetType();
    PropertyInfo propInfo = objectType.GetProperty(propertyName);
    if (propInfo == null && propertyName.Contains('.'))
    {
        string firstProp = propertyName.Substring(0, propertyName.IndexOf('.'));
        propInfo = objectType.GetProperty(firstProp);
        if (propInfo == null)//property name is invalid
        {
            throw new ArgumentException(String.Format("Property {0} is not a valid property of {1}.", firstProp, fromObject.GetType().ToString()));
        }
        return GetPropertyValue(propInfo.GetValue(fromObject, null), propertyName.Substring(propertyName.IndexOf('.') + 1));
    }
    else
    {
        return propInfo.GetValue(fromObject, null);
    }
}

很确定这可以解决您用于属性名称的任何字符串的问题,无论嵌套的程度如何,只要一切都是财产。

My internet connection was down when I need to solve the same problem, so I had to 're-invent the wheel':

static object GetPropertyValue(Object fromObject, string propertyName)
{
    Type objectType = fromObject.GetType();
    PropertyInfo propInfo = objectType.GetProperty(propertyName);
    if (propInfo == null && propertyName.Contains('.'))
    {
        string firstProp = propertyName.Substring(0, propertyName.IndexOf('.'));
        propInfo = objectType.GetProperty(firstProp);
        if (propInfo == null)//property name is invalid
        {
            throw new ArgumentException(String.Format("Property {0} is not a valid property of {1}.", firstProp, fromObject.GetType().ToString()));
        }
        return GetPropertyValue(propInfo.GetValue(fromObject, null), propertyName.Substring(propertyName.IndexOf('.') + 1));
    }
    else
    {
        return propInfo.GetValue(fromObject, null);
    }
}

Pretty sure this solves the problem for any string you use for property name, regardless of extent of nesting, as long as everything's a property.

假面具 2024-08-22 10:14:59

基于@jheddings 的原始代码,我创建了一个具有泛型类型和验证的扩展方法版本:

public static T GetPropertyValue<T>(this object sourceObject, string propertyName)
{
    if (sourceObject == null) throw new ArgumentNullException(nameof(sourceObject));
    if (string.IsNullOrWhiteSpace(propertyName)) throw new ArgumentException(nameof(propertyName));

    foreach (string currentPropertyName in propertyName.Split('.'))
    {
        if (string.IsNullOrWhiteSpace(currentPropertyName)) throw new InvalidOperationException($"Invalid property '{propertyName}'");

        PropertyInfo propertyInfo = sourceObject.GetType().GetProperty(currentPropertyName);
        if (propertyInfo == null) throw new InvalidOperationException($"Property '{currentPropertyName}' not found");

        sourceObject = propertyInfo.GetValue(sourceObject);
    }

    return sourceObject is T result ? result : default;
}

Based on the original code from @jheddings, I have created a extension method version with generic type and verifications:

public static T GetPropertyValue<T>(this object sourceObject, string propertyName)
{
    if (sourceObject == null) throw new ArgumentNullException(nameof(sourceObject));
    if (string.IsNullOrWhiteSpace(propertyName)) throw new ArgumentException(nameof(propertyName));

    foreach (string currentPropertyName in propertyName.Split('.'))
    {
        if (string.IsNullOrWhiteSpace(currentPropertyName)) throw new InvalidOperationException(
quot;Invalid property '{propertyName}'");

        PropertyInfo propertyInfo = sourceObject.GetType().GetProperty(currentPropertyName);
        if (propertyInfo == null) throw new InvalidOperationException(
quot;Property '{currentPropertyName}' not found");

        sourceObject = propertyInfo.GetValue(sourceObject);
    }

    return sourceObject is T result ? result : default;
}
寻找我们的幸福 2024-08-22 10:14:59

我编写了一个方法,该方法从输入接收一种对象类型作为参数,并返回字典

public static Dictionary<string, string> GetProperties(Type placeHolderType)
    {
        var result = new Dictionary<string, string>();
        var properties = placeHolderType.GetProperties();
        foreach (var propertyInfo in properties)
        {
            string name = propertyInfo.Name;
            string description = GetDescriptionTitle(propertyInfo);
            if (IsNonString(propertyInfo.PropertyType))
            {
                var list = GetProperties(propertyInfo.PropertyType);
                foreach (var item in list)
                {
                    result.Add($"{propertyInfo.PropertyType.Name}_{item.Key}", item.Value);
                }
            }
            else
            {
                result.Add(name, description);
            }
        }
        return result;
    }

public static bool IsNonString(Type type)
    {
        if (type == null || type == typeof(string))
            return false;
        return typeof(IPlaceHolder).IsAssignableFrom(type);
    }

private static string GetDescriptionTitle(MemberInfo memberInfo)
    {
        if (Attribute.GetCustomAttribute(memberInfo, typeof(DescriptionAttribute)) is DescriptionAttribute descriptionAttribute)
        {
            return descriptionAttribute.Description;
        }
        return memberInfo.Name;
    }

I wrote a method that received one object type as the argument from the input and returns dictionary<string,string>

public static Dictionary<string, string> GetProperties(Type placeHolderType)
    {
        var result = new Dictionary<string, string>();
        var properties = placeHolderType.GetProperties();
        foreach (var propertyInfo in properties)
        {
            string name = propertyInfo.Name;
            string description = GetDescriptionTitle(propertyInfo);
            if (IsNonString(propertyInfo.PropertyType))
            {
                var list = GetProperties(propertyInfo.PropertyType);
                foreach (var item in list)
                {
                    result.Add(
quot;{propertyInfo.PropertyType.Name}_{item.Key}", item.Value);
                }
            }
            else
            {
                result.Add(name, description);
            }
        }
        return result;
    }

public static bool IsNonString(Type type)
    {
        if (type == null || type == typeof(string))
            return false;
        return typeof(IPlaceHolder).IsAssignableFrom(type);
    }

private static string GetDescriptionTitle(MemberInfo memberInfo)
    {
        if (Attribute.GetCustomAttribute(memberInfo, typeof(DescriptionAttribute)) is DescriptionAttribute descriptionAttribute)
        {
            return descriptionAttribute.Description;
        }
        return memberInfo.Name;
    }
生生漫 2024-08-22 10:14:59
     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");
        
       var prop = src.GetType().GetProperty(propName);

        if (prop != null)
        {
            return prop.GetValue(src, null);
        }
        else
        {
            var props = src.GetType().GetProperties();

            foreach (var property in props)
            {
                var propInfo = src.GetType().GetProperty(property.Name);

                if (propInfo != null)
                {
                    var propVal = propInfo.GetValue(src, null);

                    if (src.GetType().GetProperty(property.Name).PropertyType.IsClass)
                    {
                        return GetPropertyValue(propVal, propName);
                    }

                    return propVal;
                }
            }

            return null;
        }

用法:调用部分

var emp = new Employee() { Person = new Person() { FirstName = "Ashwani" } };
var val = GetPropertyValue(emp, "名字");

以上可以查询任意级别的属性值

     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");
        
       var prop = src.GetType().GetProperty(propName);

        if (prop != null)
        {
            return prop.GetValue(src, null);
        }
        else
        {
            var props = src.GetType().GetProperties();

            foreach (var property in props)
            {
                var propInfo = src.GetType().GetProperty(property.Name);

                if (propInfo != null)
                {
                    var propVal = propInfo.GetValue(src, null);

                    if (src.GetType().GetProperty(property.Name).PropertyType.IsClass)
                    {
                        return GetPropertyValue(propVal, propName);
                    }

                    return propVal;
                }
            }

            return null;
        }

usage: calling part

var emp = new Employee() { Person = new Person() { FirstName = "Ashwani" } };
var val = GetPropertyValue(emp, "FirstName");

above can search the property value at any level

走过海棠暮 2024-08-22 10:14:59

尝试 inv.GetType().GetProperty("BillTo+Address");

Try inv.GetType().GetProperty("BillTo+Address");

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文