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)。

我认为这是一件容易的事情,但关于它为什么会这样表现的一些观点值得赞赏!

IList<;接口类型>;到列表<;实现接口类型>;

我认为这是一件容易的事情

这并不容易。至少不要容易。不允许这样做的原因最好用一个例子来解释。假设它被允许像你建议的那样完成任务:

// 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>,而ContinuationTriggerITrigger,因此编译器必须允许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>();
    }
}