给出以下对象:
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; }
}
Run Code Online (Sandbox Code Playgroud)
我想用反射Invoice来获得一个Name属性Customer.这就是我所追求的,假设这段代码可行:
Invoice inv = GetDesiredInvoice(); // magic method to get an invoice
PropertyInfo info = inv.GetType().GetProperty("BillTo.Address");
Object val = info.GetValue(inv, null);
Run Code Online (Sandbox Code Playgroud)
当然,由于"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;
}
Run Code Online (Sandbox Code Playgroud)
关于如何改进这种方法的任何想法,或解决这个问题的更好方法?
在发布后编辑,我看到了一些相关的帖子......然而,似乎没有专门解决这个问题的答案.另外,我仍然喜欢我的实施反馈.
Dev*_*evT 15
我使用此方法从属性中获取值
"属性"
"街道地址"
"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;
}
}
Run Code Online (Sandbox Code Playgroud)
这里的小提琴:https://dotnetfiddle.net/PvKRH0
Ree*_*sey 12
我其实认为你的逻辑很好.就个人而言,我可能会更改它,因此您将对象作为第一个参数传递(与PropertyInfo.GetValue更内联,因此不那么令人惊讶).
我也可能会把它称为更像GetNestedPropertyValue的东西,以明确它搜索属性堆栈.
Dom*_*see 11
我知道我参加派对有点晚了,正如其他人所说,你的实施很好
...... 对于简单的用例.
但是,我开发了一个完全解决该用例的库,Pather.CSharp.
它也可作为Nuget Package提供.
它的主要类是Resolver它的Resolve方法.
你传递一个对象,并在属性路径,它会返回所需的值.
Invoice inv = GetDesiredInvoice(); // magic method to get an invoice
var resolver = new Resolver();
object result = resolver.Resolve(inv, "BillTo.Address");
Run Code Online (Sandbox Code Playgroud)
但它也可以解析更复杂的属性路径,包括数组和字典访问.
因此,例如,如果您Customer有多个地址
public class Customer {
public String Name { get; set; }
public IEnumerable<String> Addresses { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
你可以使用第二个访问Addresses[1].
Invoice inv = GetDesiredInvoice(); // magic method to get an invoice
var resolver = new Resolver();
object result = resolver.Resolve(inv, "BillTo.Addresses[1]");
Run Code Online (Sandbox Code Playgroud)
Gab*_*ams 10
您必须访问需要使用反射的ACTUAL对象.这就是我的意思:
而不是这个:
Invoice inv = GetDesiredInvoice(); // magic method to get an invoice
PropertyInfo info = inv.GetType().GetProperty("BillTo.Address");
Object val = info.GetValue(inv, null);
Run Code Online (Sandbox Code Playgroud)
这样做(根据评论编辑):
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);
Run Code Online (Sandbox Code Playgroud)
查看这篇文章以获取更多信息: 使用反射来设置对象属性的属性
希望对派对听起来不太晚,我想补充一下我的解决方案:在这种情况下绝对使用递归
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();
}
}
Run Code Online (Sandbox Code Playgroud)
你没有解释你的"不适"的来源,但你的代码对我来说基本上是合理的.
我唯一要问的是错误处理.如果代码尝试遍历空引用或者属性名称不存在,则返回null.这隐藏了错误:很难知道它是否因为没有BillTo客户而返回null,或者因为你拼错了它"BilTo.Address"......或者因为有一个BillTo客户,并且它的地址为空!在这些情况下,我会让方法崩溃并烧掉 - 只是让异常逃脱(或者将它包装在更友好的一个中).
| 归档时间: |
|
| 查看次数: |
71510 次 |
| 最近记录: |