2

我有一个被广泛实现的接口,它有一个带有特定接口的 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)的对象。

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

4

2 回答 2

5

我认为这是一件容易的事

这是不容易的。至少没那么容易。不允许这样做的原因最好用一个例子来解释。假设允许按照您的建议执行任务:

// 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());

由于CompletionTriggersis 类型IList<ITriggers>并且ContinuationTriggerITrigger,编译器必须允许Add调用。但这会将继续触发器放入myTriggers已创建为 a 的集合中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>();
}
于 2013-02-13T01:20:06.743 回答
0

我认为,如果您要将列表定义为,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>();
    }
}
于 2013-02-13T01:33:28.010 回答