问题:

class StatesChain : IState, IHasStateList {
    private TasksChain tasks = new TasksChain();

     ...

    public IList<IState> States {
        get { return _taskChain.Tasks; }
    }

    IList<ITask> IHasTasksCollection.Tasks {
        get { return _taskChain.Tasks; } <-- ERROR! You can't do this in C#!
                                             I want to return an IList<ITask> from
                                             an IList<IStates>.
    }
}

假设 IList 返回将是只读的,我知道我要实现的目标是安全的(或者不是吗?)。有什么办法可以完成我的尝试?我不想尝试实施自己 TasksChain 算法(再次!),因为它容易出错,并且会导致代码重复。也许我可以定义一个抽象链,然后同时实现 TasksChainStatesChain 从那里?或者也许实施 Chain<T> 班级?

您将如何处理这种情况?

细节:我定义了一个 ITask 界面:

public interface ITask {
    bool Run();
    ITask FailureTask { get; }
}

IState 继承的接口 ITask:

public interface IState : ITask {
    IState FailureState { get; }
}

我也定义了一个 IHasTasksList 界面:

interface IHasTasksList {
    List<Tasks> Tasks { get; }
}

IHasStatesList:

interface IHasTasksList {
    List<Tasks> States { get; }
}

现在,我定义了一个 TasksChain, ,这是一个具有一些代码逻辑的类,可以操纵一系列任务(注意 TasksChain 是一种 ITask!):

class TasksChain : ITask, IHasTasksList {
    IList<ITask> tasks = new List<ITask>();

    ...

    public List<ITask> Tasks { get { return _tasks; } }

    ...
}

我正在实施 State 以下方式:

public class State : IState {
    private readonly TaskChain _taskChain = new TaskChain();

    public State(Precondition precondition, Execution execution) {
        _taskChain.Tasks.Add(precondition);
        _taskChain.Tasks.Add(execution);
    }

    public bool Run() {
        return _taskChain.Run();
    }

    public IState FailureState {
        get { return (IState)_taskChain.Tasks[0].FailureTask; }
    }

    ITask ITask.FailureTask {
        get { return FailureState; }
    }
}

如您所见,它利用显式接口实现来“隐藏” FailureTask 而是显示 FailureState 财产。

问题来自我也想定义一个事实 StatesChain, ,这两者都从 IStateIHasStateList (这也涉及 ITaskIHasTaskList, ,以显式接口实现),我希望它也隐藏 IHasTaskList' Tasks 只显示 IHasStateList' States. (在此之后,“问题”部分中包含的内容应该是真正的,但是我认为将其放在首位会更加友好)。

(pff ..长文本) 谢谢!

有帮助吗?

解决方案

在您遇到错误的线上,您正在尝试返回 IList<IStates> 好像这是类型的实例 IList<ITask>. 。由于两种类型是不同的(无论通用参数是相关的),因此这无自动化。

在C#3.0或以上,无法自动实现这一目标。 C#4.0添加了对协方差和违反的支持,这正是为此目的。但是,正如您指出的那样,只有在返回的集合仅阅读时才起作用。这 IList<T> 类型不能保证,因此不会注释 协变 在.NET 4.0中。

要使用C#4.0进行这项工作,您需要使用 真正的只读类型, ,在框架中具有协变量注释 - 在您的情况下,最好的选择是 IEnumerable<T> (尽管您可以使用 out T 修饰符)。

为了添加更多详细信息,在C#4.0中,您可以将接口称为协变量或相互变量。第一种情况意味着编译器将允许您执行示例中需要的转换(另一种情况对于仅写入类很有用)。这是通过将显式注释添加到接口声明中完成的(这些已适用于.NET 4.0类型)。例如,声明 IEnumerable<T>out 注释意味着它支持协方差:

public interface IEnumerable<out T> : IEnumerable { /* ... */ }

现在,编译器将允许您写作:

IEnumerable<IState> states = ...
IEnumerable<ITask> tasks = states;

其他提示

简而言之,不安全,因为“只读” IList<> 不存在(合同)。只是实现将拒绝条目,但这为时已晚,因为呼叫本身将要求接口类型参数同时是共同和违反的。

但是,您可以返回 IEnumerable<> 取而代之的是,在C#4中是协变量的。由于这足以使用LINQ,因此这不应该是一个缺点,并且可以更好地表达仅阅读性质。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top