1

そこで、オブジェクトからプロパティ パスを解析し、必要なプロパティを返し、返されたプロパティを呼び出すことができるオブジェクトstartの out パラメータを取得するコードを作成しました。source

    public static PropertyInfo GetProperty(string path, object start, out object source)
    {
        if (string.IsNullOrEmpty(path))
            throw new ArgumentException();

        source = start;
        var pType = source.GetType();
        var paths = path.Split('.');

        PropertyInfo pInfo = null;
        for (int i = 0; i < paths.Length; i++) {
            var subpath = paths[i];
            pInfo = pType.GetProperty(subpath);
            if (i < paths.Length - 1) { // wonder if there's a better way writing this to avoid this if?
                source = pInfo.GetValue(source);
                pType = source.GetType();
            }
        }
        return pInfo;
    }

ここで、次の階層があるとしましょう。

    public class Object
    {
        public string Name { get; set; }
    }
    public class GameObject : Object { }
    public class Component : Object
    {
        public GameObject gameObject { get; set; }
    }
    public class MonoBehaviour : Component { }
    public class Player : MonoBehaviour { }
    public class GameManager : MonoBehaviour
    {
        public Player player { get; set; }
    }

使用例:

        var game = new GameManager
        {
            player = new Player { gameObject = new GameObject { Name = "Stu"} }
        };

        // somewhere else...
        object source;
        var name = GetProperty("player.gameObject.Name", game, out source);
        var value = name.GetValue(source); // returns "Stu"

私の質問は次のとおりです。これは明らかにプロパティに対してのみ機能します。プロパティとフィールドの両方で機能させるにはどうすればよいですか? - 問題は、と の間でMemberInfo共通ですが、 がないため、 を返すことができません。式について読んでいますが、ここでどのように役立つかわかりません...FieldInfoPropertyInfoGetValueMemberInfo

繰り返しますが、私が探しているのは (ソースが与えられた場合) 以下を解析する機能です: X.Y.ZX、Y、Z はプロパティまたはフィールドである可能性があります。

編集:

だから私はコードを少し変更して、私が望んでいたことを行いました-しかし、それはあなたがきしむようなきれいなコードと呼ぶものではなく、出力パラメータが多すぎます:

    public static bool TryParse(string path, object start, out PropertyInfo pinfo, out FieldInfo finfo, out object source)
    {
        if (string.IsNullOrEmpty(path))
            throw new ArgumentException();

        var type = start.GetType();
        var paths = path.Split('.');

        source = start;
        pinfo = null;
        finfo = null;

        for (int i = 0; i < paths.Length; i++) {
            var subpath = paths[i];
            pinfo = type.GetProperty(subpath);
            if (pinfo == null) {
                finfo = type.GetField(subpath);
                if (finfo == null)
                    return false;
            }
            if (i < paths.Length - 1) {
                source = pinfo == null ? finfo.GetValue(source) : pinfo.GetValue(source);
                type = source.GetType();
            }
        }
        return true;
    }

使用法:

        var game = new GameManager
        {
            player = new Player { gameObject = new GameObject { Name = "Stu" } }
        };

        object source;
        PropertyInfo pinfo;
        FieldInfo finfo;
        if (TryParse("player.gameObject.Name", game, out pinfo, out finfo, out source)) {
            var value = pinfo == null ? finfo.GetValue(source) : pinfo.GetValue(source);
        }

それは私が望む解析を行いますが、もっと良いものがあるはずです...

4

2 に答える 2

2

私の無料のオープン ソース ライブラリDynamic Expressoを使用してみることができると思います。

次のように書くことができます:

var game = new GameManager
    {
        player = new Player { gameObject = new GameObject { Name = "Stu" } }
    };

var interpreter = new Interpreter();
var parameters = new[] {
            new Parameter("game", game)
            };
var result = interpreter.Eval("game.player.gameObject.Name", parameters);

解析されたものを抽出しExpressionて、プロパティ/フィールドに関する情報を取得することもできます。また、より複雑な操作 (インデクサー、関数など) もサポートしています。解析された式はコンパイルされ、1 回以上呼び出すことができます。

于 2014-04-20T11:51:29.763 に答える
1

式ツリーにある可能性があります (null のチェックとプロパティの存在のチェックはありません)。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace ExpressionTrees
{
    public static class ExpressionTreeBuilder
    {
        private static readonly IDictionary<string, Delegate> Lambdas = 
            new Dictionary<string, Delegate>();

        public static T GetValue<T, TInst>(this TInst obj, string propPath, T defVal = default(T))
        {
            var key = String.Format("{0};{1}", propPath, "str");//typeof(T).Name);
            Delegate del;
            if (!Lambdas.TryGetValue(key, out del))
            {
                var instance = Expression.Parameter(typeof(TInst), "obj");

                var currentExpression = 
                    propPath
                    .Split('.')
                    .Aggregate((Expression)instance, Expression.PropertyOrField);

                var lexpr = Expression.Lambda<Func<TInst, T>>(currentExpression, instance);

                del = lexpr.Compile();
                Lambdas.Add(key, del);
            }

            var action = (Func<TInst, T>)del;

            return action.Invoke(obj);
        }

    }
}

そして使用例:

var surv = new Survey() { id = 1, title = "adsf" , User = new User() { Name = "UserName 11"}};
var dynamicUserName = surv.GetValue<string, Survey>("User.Name");

もちろん、十分にテストされ文書化されたサードパーティのライブラリを使用することをお勧めします。このコード スニペットは単なる例です。

于 2014-04-20T16:37:04.023 に答える