考虑以下代码:
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<>
界面中声明的项目了吗?
答案 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));
同样,你可以设置扩展标志。