Reflection with list property

Asked

Viewed 146 times

2

How to change the value of the class property in the list?

My variable classPropValueList always comes void.

I’m trying to make a Reflection of every class it inherits from Coisable, to change its string-like properties.

It is possible to find the following properties in a class that inherits from Coisable:

  1. A string type property (which must be changed)
  2. A property of the type of some other class that also inherits from Coisable (this class must have its string-like properties changed, so here is the need for recursive use).
  3. A collection type property of some other class that also inherits from Coisable, and for each of the collection’s items, their properties of type string should be amended.

I then managed, through the code below, to solve scenario 1 and 2, but I had problems with the 3rd scenario. To thresh the code, I saw that in the case of example, 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
  • Can you explain a little better what you want? In the current way you need to read all the code to try to understand the problem

  • I edited the question, adding some more details...

  • 2

    By the way, two notes: 1. I liked the class name (Coisable); 2. Very good create a [mcve], great idea.

  • I honestly don’t know if it was a compliment or an ear tug, haha...

  • 1

    They were two compliments =D It’s good to have a code that you only need to copy and paste to run and understand the problems.

1 answer

4


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

Try to do this without Reflection, something like:

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

The compiler will warn 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 of the language, they chose that it would be like this and there are reasons for it. You can see in this answer what Eric Lippert says about this.

On the other hand, it is possible to make this conversion using a IEnumerable and then convert to a list using Linq. It would still be possible to make a cast using the appropriate method for this, but then it would take more Reflection yet.

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

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

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

See working on . NET Fiddle.

  • thank you very much! It worked perfectly here, but above all, I could understand better the reason and the functioning. I just had to make some changes because I’m using . Net 4.0 in a legacy project, instead of the Roslyn used in your Fiddle.

  • 1

    Ah, yes. But you took the essential, right. Converting the code is just a little validation, really secondary thing.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.