1

我们已经到了不知道如何继续的地步:

SHORT:我们有一个通用接口和一个通用接口的集合。尝试将通用接口的实现添加到集合失败。发生的事情是我得到一个编译时异常说:

无法从 TestApp.IState<T>' 转换为 TestApp.IState<TestApp.IView>'

LONG [代码示例]:

class Program
{
    static void Main(string[] args)
    {
        var coll = new StateCollection();
        var state = new SomeState();
        coll.AddState(state);
    }
}

public class StateCollection
{
    private List<StateBase<IView>> _states = new List<StateBase<IView>>();

    public void AddState<T>(StateBase<T> state) where T: IView
    {
        _states.Add(state);
    }
}

public class SomeState : StateBase<SomeView>
{

    public IView View
    {
        get;
    }
}

public class SomeView : IView
{
}

public abstract class StateBase<T> where T : IView
{
    private SomeView _view;
    public SomeView View
    {
        get { return _view; }
    }
}

public interface IView
{
}

为什么会这样?在 AddState 中,我们提到 T 必须是 IState 的一个实例。有人可以帮助我们了解为什么会发生这种情况以及如何做我们想做的事情吗?

EDIT1:我们也尝试过:

    public void AddState(IState<IView> state)
    {
        _states.Add(state);
    }

但这只是将编译时错误移动到 'coll.AddState(state)' 所以同样的事情发生在另一个地方。

EDIT2:问题!我没有给出正确的例子。Out IState 不是接口而是抽象类。对此非常抱歉!更改代码以使用抽象类

4

5 回答 5

2

第一个解决方案

public class StateCollection
    {
        private readonly List<IState<IView>> _states = new List<IState<IView>>();

        public void AddState(IState<IView> state)
        {
            _states.Add(state);
        }
    }

正如内文所建议的那样。为了让它工作,标记T为协变interface IState<T>

public interface IState<out T> where T:IView
    {
        IView View { get; }
    }

第二种解决方案:(保持课堂变化StateCollection

将界面更改IState<T>

public interface IState<out T> where T : IView
    {
        T View { get; }
    }

和类 SomeState 到

public class SomeState : IState<SomeView>
    {
        public SomeView View{ get;private set; }
    }

Edit2 的解决方案:

class Program
    {
        static void Main(string[] args)
        {
            var coll = new StateCollection();
            var state = new SomeState();
            coll.AddState(state);
            Console.ReadKey();
        }
    }

    public class StateCollection
    {
        private List<IStateBase<IView>> _states = new List<IStateBase<IView>>();

        public void AddState(IStateBase<IView> state)
        {
            _states.Add(state);
        }
    }

    public class SomeState : StateBase<SomeView>
    {
    }

    public class SomeView : IView
    {
    }

    public interface IStateBase<out T> where T : IView
    {
        T View { get; }
    }

    public abstract class StateBase<T> : IStateBase<T> where T : IView
    {
        public T View { get; set; }
    }

    public interface IView
    {
    }
于 2013-01-18T16:12:44.980 回答
2

这些变化怎么样:

public class SomeState : IState<SomeView>
{
    public SomeView View
    {
        get;
        set;
    }
} 

在 AddState 方法中使用 IView 而不是使用泛型 Type T

public void AddState(IState<IView> state)
{
    _states.Add(state);
}

out使用关键字在 IState 中使 T 协变

public interface IState<out T> where T : IView
{
    T View { get; }
}

EDIT2 的解决方案:

不知道它是否适合你,但你可以。

public class StateCollection
{
    private List<IState<IView>> _states = new List<IState<IView>>();

    public void AddState(IState<IView> state)
    {
        _states.Add(state);
    }
}

public class SomeState : StateBase<SomeView>
{
    public override SomeView View
    {
        get { return null; }
    }
}

public abstract class StateBase<T> : IState<T> where T : IView
{
   public abstract T View { get; }
}

public interface IState<out T> where T : IView
{
    T View { get; }
}
于 2013-01-18T16:13:33.573 回答
1

这看起来更像是 Add 函数的参数错误。您是否尝试过在不使用泛型的情况下声明 add 函数?继承本身应该允许它。使 AddState 函数看起来像这样:

编辑(根据 Edit2):

如前所述,继承本身应该处理泛型。只要您声明的任何类正确实现IView, or IState<IView>, 那么就不应该有任何问题......

public absract class StateBase
{
    public IView view { get; set; }

    ....
}

public Interface IView
{ ... }

public class StateCollection
{
    private List<StateBase> _states = new List<StateBase>();

    public void AddState(StateBase state)
    {
        _states.Add(state);
    }
}

public class SomeView : IView
{ ... }

等等等等等等,根据需要经常

public class SomeState : StateBase
{
    private SomeView my_view;

    public IView view
    {
        get { return (IView)SomeView; }
        set { ; }
    }
}

//program remains unchanged

在这种情况下,SomeState 仍然是一个 IState 对象,所有的 IState 对象都实现了 IView,而 SomeView 是一个 IView 对象。SomeState 在内部实现 SomeView。对我来说看起来一样,但我不知道适应与您的真实代码一起工作的效果如何。

任何其他类都将遵循相同的模型。State会实现StateBase,内部声明一个自定义View,本身需要扩展IView。这样,自定义视图上的 IView 将起作用。

来自评论:

public class BarState : StateBase
{
    private BarView my_view;

    public IView view
    {
        get { return (IView)BarView; }
        set { ; }
    }
}

public class BarView : IView
{ ... }
于 2013-01-18T16:02:21.880 回答
0

添加接口IState(非泛型)并从IState<T>. 然后声明_statesList<IState>和方法AddState(IState state)

于 2013-01-18T16:14:09.060 回答
0

(编辑:你只需要让你的 StateBase 从协变接口继承。你不能让一个类直接协变,你总是必须通过一个接口)

试试这个:

public class StateCollection
{
    private List<IState<IView>> _states = new List<IState<IView>>();

    public void AddState(IState<IView> state)   
    {
        _states.Add(state);
    }
}

public class SomeState : StateBase<SomeView>
{
}

public class SomeView : IView
{
}

public interface IState<out T> where T : IView // now covariant with T
{
    T View { get; }
}

public abstract class StateBase<T> : IState<T> where T : IView
{
    public T View { get; set; }
}

public interface IView
{
}
于 2013-01-18T16:22:11.323 回答