Search code examples
c#propertiesclassloaderdynamic-class-loaders

Port of BeanUtils to .NET


I have a system using dynamic run-time configuration of dynamically loaded types.

The system is loading Types based on XML and creating instances. It then reads "properties" from the XML file, setting these properties on the created instance. At this time, it works on simple properties directly on the instance, however, these types can have a hierarchy of settings unknown to the calling part.

I'm looking for a utils-library similar to Java BeanUtils [http://commons.apache.org/proper/commons-beanutils/]. I would want it to be able to do something like this (pseudo code):

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

Or perhaps with extensions:

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

And the reverse with Get of course.

Note that BeanUtils has it's own style of describing properties so it works for most types of properties, including lists.

Anything, or perhaps suggestions on different approach to the problem?


Solution

  • Here is a helper class which supports Lists, Dictionaries and nested Properties, you should extend it if you need to support multiple indexers (very rare cases).

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

    and here is some Examples:

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

    Nested Properties:

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

    Indexer (with multiple index):

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

    Lists:

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

    Nested Properties with Lists:

            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");
    

    Dictionaries:

            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");
    

    Dictionaries with Enumeration as Key:

        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");
    

    Enumeration as 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]");