Colin Dawson
Colin Dawson

Reputation: 465

Working with non generic parts of a generic interface

consider the following code:

public interface IStuff<T>
{
    IList<T> Items { get; set; }
    bool IsExpanded { get; set; }
}

public interface IBar
{
    string Name { get; set; }
}

public interface IFoo : IBar, IStuff<IBar>
{
}

public class MyClass : IFoo 
{
    public Name {get;set;
    public IList<IBar> Items { get; set;}
    bool IsExpanded { get; set; }
}

When I use this, what I'm actually going to do, is populate MyClass.Items with instances of IFoo, this is allowed as IFoo implements IBar, so all is good.

However there is a method that I'm working inside a control, which does not know and should not know about IBar. It only needs to know about IStuff<> Specifically that there is a list and a property.

When I'm working with the Items, I'm going to detect if the item implements IStuff like this.

public void ProcessItems( object item )
{
    IStuff<object> stuff = item as IStuff<object>;
    stuff.IsExpanded = true;
    foreach( var childItem in stuff.items )
    {
        ProcessItems( childItem );
    }
}

The problem here, is the cast into IStuff<object> does not work now, it returns null. What I want to do is work with the generic part of the interface only, I don't care about what the T is.

The question is how do I replace

IStuff<object> stuff = item as IStuff<object>;

so that I can work with the items declared in the IStuff<> interface?

Upvotes: 0

Views: 64

Answers (3)

Nico
Nico

Reputation: 3542

If you don't mind reflection, you could read the property and cast it to IEnumerable:

var listType = item.GetType().GetProperty("Items");
var enumerable = (IEnumerable)(listType.GetValue(item));

Likewise you could set the expanded flag.

Upvotes: 0

open-collar
open-collar

Reputation: 1424

Can you split IStuff into a non-generic and generic parts (that inherits from the non-generic part) and then only deal with the non-generic part in your code? E.g.

public interface IStuff
{
    IsExpanded { get; set; }
}
public interface IStuff<T> : IStuff
{
    IList<T> Items { get; set; }
}

Upvotes: 0

MakePeaceGreatAgain
MakePeaceGreatAgain

Reputation: 37050

Sounds like you need co-variance on your interface IStuff. However as IList<T> is not co-variant you may use an interface that supports covariance such as IEnumerable<T> which is co-variant since .NET 4.0:

public interface IStuff<out T>
{
    IEnumerable<T> Items { get; set; }
    bool IsExpanded { get; set; }
}

Now you can cast a an instance of IStuff<IBar> to IStuff<object>.

Upvotes: 3

Related Questions