IList<;接口类型>;到列表<;实现接口类型>;
本文关键字:gt 接口类型 lt 实现 列表 IList | 更新日期: 2023-09-27 17:58:56
我有一个被广泛实现的接口,它有一个带有特定接口的IList。不要看很多文本,请看这里:
interface ILanguage
{
IList<ITriggers> CompletionTriggers { get; set; }
}
public class Language : ILanguage
{
public Constructor()
{
CompletionTriggers = new List<CompletionTrigger>();
}
}
这基本上就是我要做的。"触发器"是一个接口的成员,它由几种类型实现。但每种类型都需要一个自定义的ITrigger实现和List(我使用IList,因为它看起来很方便)。
错误显示"缺少强制转换?",但我觉得这很奇怪,因为两者都是直接实现IList和ITrigger的对象(List和CompletionTrigger)。
我认为这是一件容易的事情,但关于它为什么会这样表现的一些观点值得赞赏!
我认为这是一件容易的事情
这并不容易。至少不要那容易。不允许这样做的原因最好用一个例子来解释。假设它被允许像你建议的那样完成任务:
// Let's make another trigger unrelated to CompletionTrigger
class ContinuationTrigger : ITrigger {
}
// This is allowed
List<CompletionTrigger> myTriggers = new List<CompletionTrigger>();
// THIS WILL NOT WORK (but let's pretend that it does)
IList<ITriggers> CompletionTriggers = myTriggers;
// Here comes trouble:
CompletionTriggers.Add(new ContinuationTrigger());
由于CompletionTriggers
的类型是IList<ITriggers>
,而ContinuationTrigger
是ITrigger
,因此编译器必须允许Add
调用。但这将在myTriggers
中设置一个延续触发器,该集合已被创建为List<CompletionTrigger>
,这是绝对不允许的。
要克服这一点,你有几个选择。最简单的方法是平等地对待ITrigger
对象,只在创建对象时进行区分。这可能很棘手,在某些情况下需要多次调度。
另一种选择是制作用于获取和设置CompletionTriggers
:元素的通用封面
void SetCompletionTriggers<T>(IList<T> triggers) where T : ITrigger {
CompletionTriggers = triggers.Cast<ITrigger>().ToList();
}
IEnumerable<T> GetCompletionTriggers<T>() where T : ITrigger {
return CompletionTriggers.Cast<T>();
}
我认为,如果您要将列表定义为IList<ITriggers>
,那么当您新建它时,它必须是new List<ITriggers>
。
如果你真的想创建一个特定类型的列表,你可以让你的界面通用
interface ITriggers
{
}
class CompletionTrigger : ITriggers
{
}
interface ILanguage<T> where T: ITriggers
{
List<T> CompletionTriggers { get; set; }
}
class Language : ILanguage<CompletionTrigger>
{
public List<CompletionTrigger> CompletionTriggers { get; set; }
public Language()
{
CompletionTriggers = new List<CompletionTrigger>();
}
}