存储在集合中实现通用接口的对象

gyu*_*isc 3 .net c#

我有许多类都在实现IWidget<T>接口.我想将它们添加到列表中,所以我定义了这样的东西:

List<IWidget<T>> _widgetList; 
Run Code Online (Sandbox Code Playgroud)

这里编译器抱怨T未被识别:

错误1找不到类型或命名空间名称"T"(您是否缺少using指令或程序集引用?)

有没有办法定义IWidget列表并仍保留通用接口?

我使用的是.NET 3.5 SP1.

cko*_*ozl 5

有几种方法可以做到这一点:

1)您需要一个非泛型的根:

public interface IWidget
{
      ...
}

public interface IWidget<T> : IWidget
{
      ...
}
Run Code Online (Sandbox Code Playgroud)

这样你就可以使用了 List<IWidget> _widgetList;


2)你可以使用dynamics或多态与对抗/协方差,但你必须遵守它所拥有的规则,<T>不能是值类型,你必须在访问后进行强制转换,而不是在添加时,像这样:

IWidget<string> xxx = ...;

var widgetListDyn = new List<IWidget<dynamic>>();
var widgetListObj = new List<IWidget<object>>();

widgetListDyn.Add(xxx);
widgetListObj.Add(xxx);
Run Code Online (Sandbox Code Playgroud)

3)或者你可以混合两种方法:

public interface IWidget : IWidget<object> {}
Run Code Online (Sandbox Code Playgroud)

并且你可以使用List<IWidget> _widgetList;这种技术,你还需要一个演员之前.add():

List<IWidget> _widgetList = new List<IWidget>();
IWidget<string> xxx = ...;
IWidget xxx1 = (IWidget)xxx;

_widgetList.Add(xxx1);
Run Code Online (Sandbox Code Playgroud)

4)你可以采取的最后一种方式是:

public class IWidgetList<T> : List<IWidget<T>> { }
Run Code Online (Sandbox Code Playgroud)

如果您打算声明创建的许多列表会使您远离丑陋的语法,那将非常有用:List<IWidget<TYPE>>而您只需使用:IWidgetList<TYPE>它就是相同的