1

動的に読み込まれる型の動的ランタイム構成を使用するシステムがあります。

システムは XML に基づいてタイプをロードし、インスタンスを作成しています。次に、XML ファイルから「プロパティ」を読み取り、作成されたインスタンスにこれらのプロパティを設定します。現時点では、インスタンスの単純なプロパティで直接動作しますが、これらの型には、呼び出し側が認識しない設定の階層が含まれている可能性があります。

Java BeanUtils [ http://commons.apache.org/proper/commons-beanutils/]に似た utils-library を探しています。次のようなことができるようにしたいと思います(疑似コード):

Util.SetProperty(someInstance, "property1.property2, someValue);

または、おそらく拡張機能を使用して:

someInstance.SetProperty("property1.property2, someValue);

そしてGetもちろん逆です。

BeanUtils にはプロパティを記述する独自のスタイルがあるため、リストを含むほとんどのタイプのプロパティで機能することに注意してください。

問題への別のアプローチに関する何か、またはおそらく提案はありますか?

4

1 に答える 1

1

リスト、辞書、およびネストされたプロパティをサポートするヘルパー クラスを次に示します。複数のインデクサーをサポートする必要がある場合は、拡張する必要があります (非常にまれなケースです)。

public static class Helper
{
    public static void SetProperty(object instance, string propery, object value)
    {
        const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
        var properties = propery.Split('.');
        var type = instance.GetType();
        object[] index = null;
        PropertyInfo property = null;

        for (var i = 0; i < properties.Length; i++)
        {
            var indexValue = Regex.Match(properties[i], @"(?<=\[)(.*?)(?=\])").Value;

            if (string.IsNullOrEmpty(indexValue))
            {
                property = type.GetProperty(properties[i], flags);
                index = null;
            }
            else
            {
                property =
                    type.GetProperty(properties[i].Replace(string.Format("[{0}]", indexValue), string.Empty),
                        flags);
                index = GetIndex(indexValue, property);
            }

            if (i < properties.Length - 1)
                instance = property.GetValue(instance, index);
            type = instance.GetType();
        }

        property.SetValue(instance, value, index);
    }

    public static object GetProperty(object instance, string propery)
    {
        const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
        var properties = propery.Split('.');
        var type = instance.GetType();

        foreach (var p in properties)
        {
            var indexValue = Regex.Match(p, @"(?<=\[)(.*?)(?=\])").Value;

            object[] index;
            PropertyInfo property;
            if (string.IsNullOrEmpty(indexValue))
            {
                property = type.GetProperty(p, flags);
                index = null;
            }
            else
            {
                property =
                    type.GetProperty(p.Replace(string.Format("[{0}]", indexValue), string.Empty),
                        flags);
                index = GetIndex(indexValue, property);
            }

            instance = property.GetValue(instance, index);
            type = instance.GetType();
        }

        return instance;
    }

    private static object[] GetIndex(string indicesValue, PropertyInfo property)
    {
        var parameters = indicesValue.Split(',');
        var parameterTypes = property.GetIndexParameters();
        var index = new object[parameterTypes.Length];

        for (var i = 0; i < parameterTypes.Length; i++)
            index[i] = parameterTypes[i].ParameterType.IsEnum
                ? Enum.Parse(parameterTypes[i].ParameterType, parameters[i])
                : Convert.ChangeType(parameters[i], parameterTypes[i].ParameterType);

        return index;
    }
}

ここにいくつかの例があります:

  public enum Qwerty
    {
        Q,W,E,R,T,Y
    }

  class A
    {
        private int[,] _array=new int[10,10];

        public B PropertyB { get; set; }

        public int this[int i, int j]
        {
            get { return _array[i, j]; }
            set { _array[i, j] = value; }
        }
    }

    class B
    {
        public int Value { get; set; }
    }

ネストされたプロパティ:

        var a = new A { PropertyB = new B() };
        Helper.SetProperty(a, "PropertyB.Value", 100);
        var value = Helper.GetProperty(a, "PropertyB.Value");

インデクサー (複数のインデックスを使用):

        var a = new A { PropertyB = new B() };
        Helper.SetProperty(a, "Item[1,1]", 100);
        var value = Helper.GetProperty(a, "Item[1,1]");

リスト:

        var list = new List<int>() { 0, 1, 2, 3, 4 };
        Helper.SetProperty(list, "Item[2]", 200);
        var value = Helper.GetProperty(list, "Item[2]");

リストを持つネストされたプロパティ:

        var list = new List<A>() { new A { PropertyB = new B() } };
        Helper.SetProperty(list, "Item[0].PropertyB.Value", 75);
        var value = Helper.GetProperty(list, "Item[0].PropertyB.Value");

辞書:

        var dic = new Dictionary<int, A> { { 100, new A { PropertyB = new B() } } };
        var newA = new A { PropertyB = new B() { Value = 45 } };
        Helper.SetProperty(dic, "Item[100]", newA);
        var value = Helper.GetProperty(dic, "Item[100].PropertyB.Value");

列挙をキーとする辞書:

    var dic = new Dictionary<Qwerty, A> { { Qwerty.Q, new A { PropertyB = new B() } } };
    var newA = new A { PropertyB = new B() { Value = 45 } };
    Helper.SetProperty(dic, "Item[Q]", newA);
    var value = Helper.GetProperty(dic, "Item[Q].PropertyB.Value");

値としての列挙:

    var list = new List<Qwerty>() { Qwerty.Q, Qwerty.W, Qwerty.E, Qwerty.R, Qwerty.T, Qwerty.Y };
    Helper.SetProperty(list, "Item[2]", Qwerty.Q);
    var value = Helper.GetProperty(list, "Item[2]");
于 2014-09-21T19:19:08.613 に答える