Reflection with list property

2

How can I change the value of the class property in the list?

My variable classPropValueList always comes null.

I'm trying to make a reflection of every class that inherits from Coisable , to change its string properties.

You can find the following properties in a class that inherits from Coisable :

  • A string property (which should be changed)
  • A property of the type of some other class that also inherits from Coisable (this class should have its string properties changed, so here is the need to use recursion).
  • A collection-type property of some other class that also inherits from Coisable , and for each of the items in the collection, its string properties should be changed.
  • I then managed, through the code below, to solve scenarios 1 and 2, but I had problems with the 3rd scenario. In the debug section of the code, I saw that in the example case, it is possible to enter the third condition, but when trying to get the list, it always comes null.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    public class Program
    {
        public static void Main()
        {
            var coisa1 = new MyClass3
            {
                MyProperty1 = "Valor Original 1",
                MyProperty2 = new MyClass1
                {
                    MyProperty = "Valor Original 2"
                },
                MyProperty3 = new List<MyClass2> 
                {
                    new MyClass2 
                    {
                        MyProperty = "Valor Original 3"
                    }
                }
            };
    
            Console.WriteLine("--- Valores Originais ---");
            Console.WriteLine(coisa1.MyProperty1);
            Console.WriteLine(coisa1.MyProperty2.MyProperty);
            Console.WriteLine(coisa1.MyProperty3.First().MyProperty);
    
            Console.WriteLine();
    
            coisa1.Coise();
    
    
            Console.WriteLine("--- Novos Valores ---");
            Console.WriteLine(coisa1.MyProperty1);
            Console.WriteLine(coisa1.MyProperty2.MyProperty);
            Console.WriteLine(coisa1.MyProperty3.First().MyProperty);
    
        }
    }
    
    // #region Minhas Classes
    
        public class Coisable
        {
        }
    
    
        public class MyClass1 : Coisable
        {
           public string MyProperty { get; set; }
        }
    
        public class MyClass2 : Coisable
        {
           public string MyProperty { get; set; }
        }
    
        public class MyClass3 : Coisable
        {
            public string MyProperty1 { get; set; }
            public MyClass1 MyProperty2 { get; set; }
            public List<MyClass2> MyProperty3 { get; set; }
        }
    
        // #endregion
    
        // #region Reflection
    
        public static class CoisableExt
        {
            public static void Coise(this Coisable coisableClass) {
                foreach (var propertyInfo in coisableClass.GetType().GetProperties())
                {
                    if(typeof(string).IsAssignableFrom(propertyInfo.PropertyType))
                    {
                        var propValue = propertyInfo.GetValue(coisableClass, null).ToString();
                        propValue = "Novo Valor";
                        propertyInfo.SetValue(coisableClass, propValue, null);
                    }
                    else if(typeof(Coisable).IsAssignableFrom(propertyInfo.PropertyType))
                    {
                        var classPropValue = propertyInfo.GetValue(coisableClass, null) as Coisable;
                        classPropValue.Coise();
                    }
                    else if (typeof(IEnumerable<Coisable>).IsAssignableFrom(propertyInfo.PropertyType))
                    {
                        var classPropValueList = propertyInfo.GetValue(coisableClass, null) as List<Coisable>;
                        if(classPropValueList != null && classPropValueList.Any())
                        {
                            classPropValueList.ForEach(classPropValueItem =>
                            {
                               classPropValueItem.Coise();
                            });
                        }
                    }
                }
            }
        }
    
        // #endregion
    
        
    asked by anonymous 08.05.2017 / 15:24

    1 answer

    4

    The problem here is that you can not convert a list of objects of a certain type to a list of objects of the base type.

    Try doing this without reflection , something like:

    var listaMyClass = new List<MyClass2>(); 
    var listaCoisable = listaMyClass as List<Coisable>;
    

    The compiler will warn you that this type of conversion is not possible and that is why the variable classPropValueList receives null instead of the expected value.

    This is a matter of design language, have chosen that would be so and there are reasons for this. You can see in this answer what Eric Lippert talks about.

    Conversely, you can do this by using IEnumerable and then convert to a list using Linq. It would still be possible to cast cast using the appropriate method for this, but it would still require cast yet.

    In particular, I think the idea of using IEnumerable is a good way out of your case.

    Then just change as List<Coisable> to as IEnumerable<Coisable> and then use ToList() to convert the sequence to a list.

    var classPropValueList = (propertyInfo.GetValue(coisableClass, null) 
                                as IEnumerable<Coisable>)?.ToList();
    

    See working in .NET Fiddle .

        
    08.05.2017 / 16:34