2

次のコードは、私が書いているプログラムの簡単な例です。

public class Y
{ }

public class X : Y
{ }

public class W : Y
{ }

public interface IAaa<T>
    where T : Y
{
    void Execute(T ppp);
}

public abstract class Aaa<T> : IAaa<T>
    where T : Y
{
    public abstract void Execute(T ppp);
}

public class Bbb : Aaa<X>
{
    public override void Execute(X ppp)
    { }
}

public class Ccc : Aaa<W>
{
    public override void Execute(W ppp)
    { }
}

public class Factory 
{
    public static IAaa<Y> Get(bool b)
    {
        if(b)
            return new Bbb();
        else
            return new Ccc();
    }
}

class Program
{
    static void Main(string[] args)
    {
        IAaa<Y> aa;
        aa = Factory.Get(true);
    }
}

コンパイルすると、次のエラーが発生します

エラー CS0266: 型 'ConsoleApplication3.Bbb' を 'ConsoleApplication3.IAaa' に暗黙的に変換できません。明示的な変換が存在します (キャストがありませんか?)

エラー CS0266: 型 'ConsoleApplication3.Ccc' を 'ConsoleApplication3.IAaa' に暗黙的に変換できません。明示的な変換が存在します (キャストがありませんか?)

それを機能させる方法はありますか?

4

3 に答える 3

1

しようとしている方法でインターフェイスを使用することはできません。covariance/contravarianceをルックアップすると、可能なこととは逆のことをしようとしています (インターフェイスにある可能性がありますが、の<in T>ように使用しようとしています<out T>)。

クラスBbbを例にとると、Execute(X)メソッドがあります。Yそれに( である場合もそうでない場合もある)を渡そうとするとどうなるでしょうXか? その場合に何が起こるべきかをコードで定義したことがないため、コンパイラはそれを許可しません。

別のインターフェイスを作成して実装することで、必要なことを行うことができますIAaa。例えば

public interface IAaa
{
    void Execute(Y ppp);
}

おそらく次のように実装されているため、無効な型で呼び出そうとすると、キャスト例外がスローされます。

void Main()
{
        IAaa aa;
        aa = Factory.Get(true);
}

public class Y
{ }

public class X : Y
{ }

public class W : Y
{ }

public interface IAaa<T> : IAaa
    where T : Y
{
    void Execute(T ppp);
}

public interface IAaa
{
    void Execute(Y ppp);
}

public abstract class Aaa<T> : IAaa<T>
    where T : Y
{
    public abstract void Execute(T ppp);
    void IAaa.Execute(Y ppp)
    {
        this.Execute(ppp);
    }
    protected abstract void Execute(Y ppp);
}

public class Bbb : Aaa<X>
{
    public override void Execute(X ppp)
    { }
    protected override void Execute(Y ppp)
    {
        this.Execute((X)ppp);
    }
}

public class Ccc : Aaa<W>
{
    public override void Execute(W ppp)
    { }
    protected override void Execute(Y ppp)
    {
        this.Execute((W)ppp);
    }
}

public class Factory 
{
    public static IAaa Get(bool b)
    {
        if(b)
            return new Bbb();
        else
            return new Ccc();
    }
}
于 2013-04-11T11:58:05.367 に答える
0

( ) にキャストするIAaa<Y>と、コードがコンパイルされます。ただし、これは機能せず、実行時に失敗します。なんで?あなたのクラスBbbCccは特殊なクラスであり、Execute メソッドは のすべてのタイプを処理することはできませんAaa。C# / コンパイラーに伝える必要があります。

アップデート:

ジェネリック ファクトリを持つことで、IAaa の特殊なインスタンスを取得でき、コードが機能するはずです。TRUE または FALSE を Factory に渡すと、Program既に型がわかっているため、使用するインターフェイス実装の型を C# に明示的に伝える必要があります。(それに応じて Factory クラスをリファクタリングします。コンパイルする必要があるものを送信しているだけです)

public class Y
{ }

public class X : Y
{ }

public class W : Y
{ }

public interface IAaa<T>
    where T : Y
{
    void Execute(T ppp);
}

public abstract class Aaa<T> : IAaa<T>
    where T : Y
{
    public abstract void Execute(T ppp);
}

public class Bbb : Aaa<X>
{
    public override void Execute(X ppp)
    { }
}

public class Ccc : Aaa<W>
{
    public override void Execute(W ppp)
    { }
}

public class Factory<T> where T : Y
{
    public static IAaa<T> Get(bool b)
    {
        if(b)
            return (IAaa<T>)new Bbb();
        else
            return (IAaa<T>)new Ccc();
    }
}

class Program
{
    static void Main(string[] args)
    {
        IAaa<X> aa;
        aa = Factory<X>.Get(true);
    }
}

更新 2

Factory クラスをリファクタリングする方法の例:

public class Factory<T, U>
    where T : Y
    where U : Aaa<T>, new()
{
    public static IAaa<T> Get()
    {
        return (IAaa<T>)new U();
    }
}

class Program
{
    static void Main(string[] args)
    {
        IAaa<X> aa;
        aa = Factory<X, Bbb>.Get();
    }
}
于 2013-04-11T11:54:04.050 に答える