通过反射获得完整的“路径”(C#)

时间:2012-12-28 16:39:19

标签: c# reflection

是否有可能获得完整的路径'通过反思?

示例假设我有以下类/属性。

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

4 个答案:

答案 0 :(得分:4)

如果您愿意使用Expression<Func<T>>,那么是的,应该很简单。

做这样的事情:

 public string GetFullPath<T>(Expression<Func<T>> action) {
  return action.Body.ToString();
}

var fullPath = GetFullPath(() => m.Address.Line1);

这并不能完全满足您的需求,但它会非常接近,您可以删除不想要的位。

我会在那个对象中挖掘一下,看看是否有更清洁的方法让你更接近你想要的东西。

答案 1 :(得分:1)

没有

问题在于,当您传递m.Address.Line1实例时,您收到的所有方法都是Line实例,并且无法找出哪些实例引用它。

当然,你可以让这个方法接受像MyMethod(m, "Address", "Line1")这样的东西,但这可能会破坏整个目的(很难知道,因为你没有说明你为什么要这样做)

你可能会对Expression<T>感到幸运。

答案 2 :(得分:0)

让我首先确保我理解你的问题......如果你想通过将一个字符串如“m.Address.Line1”传递给某个函数来获取m.Address.Line1的值,那么是的,你可以做那。如果您尝试从Line1开始并向上导航树以查看哪些对象引用它,那么这是一个更难的问题,我无法帮助。

如果是第一种情况,那么我在CodeProject上写的一篇文章中填写文本模板。代码本身有点复杂,所以我不会在这里发布,但这里是链接:

http://www.codeproject.com/Articles/505428/A-lightweight-recursive-text-template-data-formatt

代码本质上会拆分你在每个“。”传入的字符串。并递归地向下导航对象树以找到您要查找的值。它还支持IEnumerable之类的内容,但仅用于填写模板(即,无法导航到列表的特定索引)。

答案 3 :(得分:0)

我假设“地址”是不存在的东西,因为早先你说过Class有三个字符串属性! 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;
        }
    }

}