0

リフレクションによって完全な「パス」を取得することは可能ですか?

例として、以下のクラス/プロパティがあると想像してください。

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

4 に答える 4

6

あなたがそれを使用する気があるならExpression<Func<T>>、そうです、それは単純なはずです。

次のようなことをしてください。

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

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

それはあなたが望むものを正確に与えるわけではありませんが、それは非常に近くなり、あなたはあなたが望まないビットを取り除くことができます。

そのオブジェクトをもう少し掘り下げて、必要なものに近づけるためのよりクリーンな方法があるかどうかを確認します。

于 2012-12-28T16:55:47.540 に答える
1

いいえ。

問題は、インスタンスを渡すときにm.Address.Line1、メソッドが受け取るのはLineインスタンスだけであり、どのインスタンスがそれを参照しているかを見つける方法がないことです。

もちろん、メソッドに次のようなものを受け入れるようにすることもできますが、MyMethod(m, "Address", "Line1")それでは目的全体が無効になる可能性があります(なぜこれが必要なのかを言わなかったため、わかりにくい)。

ただし、運が良かったかもしれませんExpression<T>

于 2012-12-28T16:45:55.970 に答える
0

クラスには3つの文字列プロパティがあると前に言ったように、「アドレス」は存在しないものだと思いました。Line1、Line2、Line3

クラスの名前を保持するプロパティ「Name」を1つ追加しました。これは、コントロールNameを持つのとまったく同じであるため、そのNameプロパティに基づいてオブジェクトにタグを付けることができます。

さらに、作成されたオブジェクトを追跡する必要があるような出力が必要な場合は、リストタイプを選択しました。

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

}
于 2012-12-28T16:52:56.497 に答える
0

まず、あなたの質問を理解していることを確認しましょう... m.Address.Line1"m.Address.Line1"などの文字列を関数に渡しての値を取得したい場合は、そうすることができます。Line1から始めてツリーを上に移動し、どのオブジェクトがそれを参照しているかを確認しようとしている場合、これははるかに難しい質問であり、私は仕方がありません。

それが最初のケースである場合、私はテキストテンプレートに記入するCodeProjectで書いた記事でこれを行います。コード自体は少し複雑なので、ここには投稿しませんが、リンクは次のとおりです。

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

コードは基本的に、各「。」で渡す文字列を分割します。オブジェクトツリーを再帰的に下に移動して、探している値を見つけます。またIEnumerable、テンプレートへの入力のみをサポートします(つまり、リストの特定のインデックスに移動することはできません)。

于 2012-12-28T16:41:52.360 に答える