1

続行する方法がわからないところまで来ました。

短い: ジェネリック インターフェイスとジェネリック インターフェイスのコレクションがあります。ジェネリック インターフェイスの実装をコレクションに追加しようとすると失敗します。何が起こるかというと、次のようなコンパイル時の例外が発生します。

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 SomeState : IState<SomeView>
{
    public SomeView View
    {
        get;
        set;
    }
} 

ジェネリックタイプTを使用する代わりに、AddStateメソッドでIViewを使用します

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 に答える
2

最初の解決策

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

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

Nevyn の提案どおり。T動作させるには、共変としてマークしますinterface IState<T>

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

2番目の解決策:(クラスで変更を続ける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 に答える
1

これは、Add 関数のパラメーター エラーのように見えます。ジェネリックを使用せずに add 関数を宣言しようとしましたか? 継承自体がそれを許可する必要があります。AddState 関数を次のようにします。

編集 (Edit2 による):

前述のように、継承自体がジェネリックを処理する必要があります。IView宣言したクラスが、またはを適切に実装している限り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 オブジェクトであり、すべての ISt​​ate オブジェクトは IView を実装しており、SomeView は IView オブジェクトです。SomeState は SomeView を内部的に実装しています。私には同じように見えますが、実際のコードで適応がどの程度うまく機能するかはわかりません。

他のクラスは同じモデルに従います。State は StateBase を実装し、それ自体が 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>ます。次に、メソッド_statesとして宣言しますList<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 に答える