在 C# 中使用反射获取嵌套对象的属性
给定以下对象:
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
来获取 Customer
的 Name
属性。这就是我所追求的,假设此代码可以工作:
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(16)
我使用以下方法从(嵌套类)属性中获取值,例如
"Property"
"Address.Street"
"Address.Country.Name" >
这是小提琴:https://dotnetfiddle.net/PvKRH0
I use following method to get the values from (nested classes) properties like
"Property"
"Address.Street"
"Address.Country.Name"
Here is the Fiddle: https://dotnetfiddle.net/PvKRH0
我知道我参加聚会有点晚了,正如其他人所说,你的实现很好
...用于简单用例。
不过,我开发了一个库,可以准确解决该用例,Pather.CSharp。
它也可以作为 Nuget 包 提供。
它的主类是
Resolver
及其Resolve
方法。您向其传递一个对象和属性路径,它将返回所需值。
但它还可以解析更复杂的属性路径,包括数组和字典访问。
因此,例如,如果您的
客户
有多个地址,您可以使用
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 itsResolve
method.You pass it an object and the property path, and it will return the desired value.
But it can also resolve more complex property paths, including array and dictionary access.
So, for example, if your
Customer
had multiple addressesyou could access the second one using
Addresses[1]
.其实我觉得你的逻辑很好。就我个人而言,我可能会对其进行更改,以便将对象作为第一个参数传递(这与 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.
您必须访问需要使用反射的实际对象。这就是我的意思:
而不是这样:
这样做(根据评论编辑):
查看这篇文章以获取更多信息:
使用反射设置 a 的属性对象的属性
You have to access the ACTUAL object that you need to use reflection on. Here is what I mean:
Instead of this:
Do this (edited based on comment):
Look at this post for more information:
Using reflection to set a property of a property of an object
为了避免听起来太晚,我想添加我的解决方案:
在这种情况下肯定使用递归
In hopes of not sounding too late to the party, I would like to add my solution:
Definitely use recursion in this situation
您没有解释“不适”的根源,但您的代码对我来说基本上看起来不错。
我唯一质疑的是错误处理。如果代码尝试遍历 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).
这是另一个实现,如果嵌套属性是枚举器,它将跳过并继续深入。字符串类型的属性不受枚举检查的影响。
基于这个问题和
我在 MVC 项目中使用它来动态排序我的数据,只需传递要排序的属性
示例:
其中 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.
based on this question and on
I use this in a MVC project to dynamically Order my data by simply passing the Property to sort by
Example:
where BookingItems is a list of objects.
如果他们请求一个不存在的属性,我实际上会抛出异常。按照您的编码方式,如果我调用 GetPropValue 并且它返回 null,我不知道这是否意味着该属性不存在,或者该属性确实存在但其值为 null。
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.
我想分享我的解决方案,尽管可能为时已晚。该解决方案主要是检查嵌套属性是否存在。但如果需要,可以轻松调整它以返回属性值。
我必须参考一些帖子才能提出这个解决方案。我认为这适用于多个嵌套属性类型。
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.
I had to refer to few posts to come up with this solution. I think this will work for multiple nested property types.
当我需要解决同样的问题时,我的互联网连接中断了,所以我不得不“重新发明轮子”:
很确定这可以解决您用于属性名称的任何字符串的问题,无论嵌套的程度如何,只要一切都是财产。
My internet connection was down when I need to solve the same problem, so I had to 're-invent the wheel':
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.
基于@jheddings 的原始代码,我创建了一个具有泛型类型和验证的扩展方法版本:
Based on the original code from @jheddings, I have created a extension method version with generic type and verifications:
我编写了一个方法,该方法从输入接收一种对象类型作为参数,并返回字典
I wrote a method that received one object type as the argument from the input and returns dictionary<string,string>
用法:调用部分
var emp = new Employee() { Person = new Person() { FirstName = "Ashwani" } };
var val = GetPropertyValue(emp, "名字");
以上可以查询任意级别的属性值
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
尝试 inv.GetType().GetProperty("BillTo+Address");
Try
inv.GetType().GetProperty("BillTo+Address");