使用通用接口的非通用部分

时间:2016-10-06 10:32:11

标签: c# generics reflection interface

考虑以下代码:

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; }
}

当我使用它时,我实际要做的是,MyClass.Items填充IFoo个实例,这是IFoo实现IBar所允许的,所以一切都很好。

然而,有一种方法我在控件中工作,它不知道也不应该知道IBar。它只需要知道IStuff<>特别是有一个列表和一个属性。

当我使用Items时,我将检测该项目是否实现了IStuff

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

这里的问题是,转换为IStuff<object>现在不起作用,它返回null。 我想要做的只是使用界面的通用部分,我不关心T是什么。

问题是如何替换

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

这样我就可以使用IStuff<>界面中声明的项目了吗?

3 个答案:

答案 0 :(得分:3)

您的界面IStuff上需要co-variance。但是,由于IList<T>不是共变体,因此您可以使用支持协方差的接口,例如IEnumerable<T>,其中自.NET 4.0以来的共变体:

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

现在,您可以将IStuff<IBar>的实例转换为IStuff<object>

答案 1 :(得分:0)

您可以将IStuff拆分为非泛型和通用部分(继承自非泛型部分),然后只处理代码中的非泛型部分吗? E.g。

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

答案 2 :(得分:0)

如果你不介意反思,你可以阅读该属性并将其投射到IEnumerable

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

同样,你可以设置扩展标志。