How do I use reflection to properly cast an unknown property to a generic list that derives from a common base?

亡梦爱人 提交于 2019-12-11 06:38:32

问题


Say I have the following:

public class MyContainer
{
    public string ContainerName { get; set; }
    public IList<Square> MySquares { get; set; }
    public IList<Circle> MyCircles { get; set; }
    public MyContainer()
    {
        MySquares = new List<Square>();
        MyCircles = new List<Circle>();
    }
}

public class Shape
{
    public int Area { get; set; }
}

public class Square : Shape
{
}

public class Circle : Shape
{
}

And now I have a function like so:

private static void Collect(MyContainer container)
{
    var properties = container.GetType().GetProperties();
    foreach (var property in properties)
    {
        if (property.PropertyType.IsGenericType &&
            property.PropertyType.GetGenericTypeDefinition() == typeof(IList<>) &&
            typeof(Shape).IsAssignableFrom(property.PropertyType.GetGenericArguments()[0]))
        {
            var t = property.GetValue(container, null) as List<Square>;
            if (t != null)
            {
                foreach (Shape shape in t)
                {
                    Console.WriteLine(shape.Area);
                }
            }
        }
    }

This works the way I want when I get to the MySquares property, however I was hoping to cast the following way instead:

var t = property.GetValue(container, null) as List<Shape>;

I was hoping that it would cycle through all of MyContainer's properties that have a similar list. Any way I can do this?


回答1:


As I suggested in my comment, using a covariant interface allows you to accomplish this.

Covariance/Contravariance: http://msdn.microsoft.com/en-us/library/ee207183.aspx
See also: Covariance and IList

Working Sample

namespace Covariance
{
    public class MyContainer
    {
        public string ContainerName { get; set; }
        public IList<Square> MySquares { get; set; }
        public IList<Circle> MyCircles { get; set; }
        public MyContainer() {
            MySquares = new List<Square>();
            MyCircles = new List<Circle>();
        }
    }

    public class Shape
    {
        public int Area { get; set; }
    }

    public class Square : Shape
    {
    }

    public class Circle : Shape
    {
    }   

    class Program
    {
        static void Main( string[] args ) {

            MyContainer mc = new MyContainer();
            mc.MyCircles.Add( new Circle { Area = 60 } );

            Collect( mc );
            Console.ReadLine();
        }

        private static void Collect( MyContainer container ) {
            var properties = container.GetType().GetProperties();
            foreach( var property in properties ) {
                if( property.PropertyType.IsGenericType &&
                    property.PropertyType.GetGenericTypeDefinition() == typeof( IList<> ) &&
                    typeof( Shape ).IsAssignableFrom( property.PropertyType.GetGenericArguments()[0] ) ) {
                    var t = property.GetValue( container, null ) as IEnumerable<Shape>;
                    if( t != null ) {
                        foreach( Shape shape in t ) {
                            Console.WriteLine( shape.Area );
                        }
                    }
                }
            }
        }
    }
}



回答2:


If you change the GetValue line to the following it works:

var t = property.GetValue(container, null) as IEnumerable<Shape>;

I tested it with the following code:

var c = new MyContainer();
c.MySquares.Add(new Square() { Area = 5, });
c.MySquares.Add(new Square() { Area = 7, });
c.MySquares.Add(new Square() { Area = 11, });
c.MyCircles.Add(new Circle() { Area = 1, });
c.MyCircles.Add(new Circle() { Area = 2, });
c.MyCircles.Add(new Circle() { Area = 3, });
Collect(c);

And got these results:

5
7
11
1
2
3


来源:https://stackoverflow.com/questions/11787972/how-do-i-use-reflection-to-properly-cast-an-unknown-property-to-a-generic-list-t

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!