Reputation: 744
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?
Upvotes: 1
Views: 852
Reputation: 54417
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
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 );
}
}
}
}
}
}
}
Upvotes: 2
Reputation: 117175
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
Upvotes: 2