是否有可能通过反射获得完整的'路径' ?
示例假设我有以下类/属性:
public class Member
{
public string Name;
public Address Address;
}
public class Address
{
public string Line1;
public string Line2;
public string Line3;
}
假设我有一个名为m
的类实例。是否可以获得完整路径为"Member.Address。Line1"(作为字符串),通过反射,只是通过某种方式传递m.Address.Line1
?
如果你愿意使用Expression<Func<T>>
,那么是的,它应该很简单。
就像这样做:
public string GetFullPath<T>(Expression<Func<T>> action) {
return action.Body.ToString();
}
var fullPath = GetFullPath(() => m.Address.Line1);
这不是你想要的,但它会非常接近,你可以删除你不需要的部分。
我再深入研究一下这个对象看看有没有更简洁的方法让你更接近你想要的
No.
问题是当你传递m.Address.Line1
实例时,你的方法接收到的都是Line
实例,它没有办法找出哪些实例引用了它。
当然,您可以使该方法接受MyMethod(m, "Address", "Line1")
之类的内容,但这可能会破坏整个目的(很难知道,因为您没有说明为什么要这样做)
使用Expression<T>
可能会有一些运气。
让我先确定我理解了你的问题…如果你想通过传递一个字符串来获取m.Address.Line1
的值,比如"m.d address"。Line1"到某个函数,那么你可以这样做。如果你想从Line1开始,然后在树中导航,看看有什么对象引用它,那么这是一个更难的问题,我无能为力。
如果是第一种情况,那么我在CodeProject上写的一篇填充文本模板的文章中这样做。代码本身有点复杂,所以我不会在这里发布它,但这里是链接:
http://www.codeproject.com/Articles/505428/A-lightweight-recursive-text-template-data-formatt代码本质上拆分了您在每个"。"处传递的字符串,并递归地沿着对象树导航以定位您正在寻找的值。它也支持IEnumerable
之类的东西,但只支持填充模板(也就是说,您不能导航到列表的特定索引)。
我假设"地址"是不存在的东西,正如之前你说的,类有三个字符串属性!Line1, Line2, Line3
我添加了一个额外的属性"Name"来保存类的名称,它与控件名称完全相同,因此我们可以根据该Name属性标记对象,
另外,如果您需要这样的输出,您必须跟踪创建的对象,为此我首选List类型。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace ConsoleApplication4
{
class Member
{
public string Line1 { get; set; }
public string Line2 { get; set; }
public string Line3 { get; set; }
public string Name { get; set; }
}
static class Program
{
private static readonly List<object> MyRefObjHolder = new List<object>();
private static void Main()
{
Member m = new Member {Line1 = "line1", Line2 = "line2", Line3 = "line3", Name = "m"};
Member n = new Member {Line1 = "line1", Line2 = "line2", Line3 = "line3", Name = "n"};
MyRefObjHolder.Add(m);
MyRefObjHolder.Add(n);
string tmp1 = GetCompleteNameWithProperty("m.Line1");
string tmp2 = GetCompleteNameWithProperty("n.Line1");
Console.WriteLine(tmp1); // prints : Member.Line1
Console.WriteLine(tmp2); // prints : Member.Line2
Console.Read();
}
public static string GetCompleteNameWithProperty(string objref)
{
string[] obj = objref.Split('.');
if (obj.Length < 2)
{
return null;
}
string className = obj[obj.Length - 2];
string propName = obj[obj.Length - 1];
string typeName = null;
foreach (object o in MyRefObjHolder)
{
Type type = o.GetType();
object name = type.GetProperty("Name").GetValue(o, null);
if (name != null && name is string && (string) name == className)
{
typeName = type.Name;
}
}
//linq based solution, replce the foreach loop with linq one :P
//string typeName = (from o in myRefObjHolder select o.GetType() into type where type.GetProperty(propName) != null select type.Name).FirstOrDefault();
return typeName != null ? string.Format("{0}.{1}", typeName, propName) : null;
}
}
}