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 回答