0

このかなり基本的な質問で申し訳ありませんが、ドキュメントが見つかりませんでした。適切な用語を知らないからかもしれません。

クラス構造:

class D{}

abstract class A<T>{}
class B<T> : A<T> {}
class C : B<D> {}

C を返すファクトリ メソッドを作成しようとしましたが、全体的な戻り値の型は A でなければなりません。残念ながら、継承構造は完全に共変であるように見えますが、この実装ではコンパイル エラーが発生します。

public A<T> FactoryMethod()
{
   return new C();
}

より具体的には、入力値に基づいて 3 つのクラスすべてを生成できるファクトリを実装しようとしていますが、ジェネリック機能を取得する必要があります。

public A<T> FactoryMethod(int i, Type K)
{
   if(i == 1)
      return new A<K>():

   if(i == 2)
      return new B<K>():

   if(i == 3)
      return new C():
}

アップデート

次のように 3 つのオブジェクトを作成する必要があります。

A<string> first = FactoryMethod(1, string);
A<int> second = FactoryMethod(2, int);
A<int> third = FactoryMethod(3, int);
4

3 に答える 3

2

を含むクラスのスコープでは、FactoryMethod意味Tがありません。型として使用するには、のジェネリック パラメータを指定する必要がありますA

この場合、Cis B<D>、およびB<D>isであるため、戻り値の型としてA<D>使用します。A<D>

2 番目の質問については、ファクトリ メソッドをジェネリックにすると、必要なものが得られると思います。

public class A<T> {}

public class B<T> : A<T> {}

public class C : B<D> {}

public class D {}

public class Test
{
    public static A<T> FactoryMethod<T>(int i)
    {
       if(i == 1)
          return new A<T>();
       if(i == 2)
          return new B<T>();
       if(i == 3)
          return (A<T>)(object)new C();
       return null;
    }

    public static void Main()
    {
        A<string> first = FactoryMethod<string>(1);
        A<int> second = FactoryMethod<int>(2);
        A<D> third = FactoryMethod<D>(3);
    }
}

C( A<D>) は一部に代入できないため(A<T>コンパイラーは常にisを渡すことを認識していません) 3、これはタイプセーフではありません。TD

于 2015-08-20T19:06:07.180 に答える
2

CバインドされたタイプのサブクラスA<D>です。したがって、以下が有効です。

public A<D> FactoryMethod()
{
   return new C();
}

であると安全に言えるからCですA<D>。ただし、ジェネリック型ではなく、任意の型になる可能性があるため、 T がジェネリック引数でCあるオープン型に変換することはできません。A<T>T

ただし、以下は有効です。

public A<T> FactoryMethod()
{
   return new B<T>();
}

B<T>もオープンジェネリック型であるため、 anyはB<T>ですA<T>


更新に基づいて、ファクトリ メソッドを次のように記述できます。

public A<T> FactoryMethod<T>(int i)
{
   if(i == 1)
      return new A<T>():
   if(i == 2)
      return new B<T>():
   if(i == 3) 
      return (A<T>)(object)new C():
      // The cast to object gets rid of compile time checking,
      // but will throw an InvalidCastExceptoin if T is not D
}

これは、ケース 3 の奇妙なハックでは少し醜いです。次に、次のように呼び出します。

A<string> first = FactoryMethod<string>(1);
A<int> second = FactoryMethod<int>(2);
A<int> third = FactoryMethod<int>(3); // InvalidCastException!
于 2015-08-20T19:09:42.540 に答える
1

これを考えると:

class D{}

class A<T>{}
class B<T> : A<T> {}
class C : B<D> {}
enum openT
{
    level1, level2
}

あなたはこれを探しているかもしれないと思います:

public A<T> FactoryMethod<T>(openT i)
{
   if(i == openT.level1)
      return new A<T>():

   if(i == openT.level2)
      return new B<T>():

}

public A<D> FactoryMethod()
{
    return new C():
}

public static void Main()
{
    A<string> first = OpenFactoryMethod<string>(1);
    A<int> second = OpenFactoryMethod<int>(2);
    A<D> third = FactoryMethod();
}

A を構築しようとしているため、 A を抽象化できないことに注意してください。

ただし、C は閉じた型であるため、ここで実際に何を達成しようとしているのかわかりません。したがって、ファクトリ メソッドは意味を成しません。

更新しました

以下は、あなたが探しているものに近いかもしれません:

public TAofT FactoryMethod<TAofT, T>() where TAofT : A<T>, new()
{
    return new TAofT():
}

public static void Main()
{
    A<string> first = FactoryMethod<A<string>, string>();
    A<int> second = FactoryMethod<B<int>, int>();
    A<D> third = FactoryMethod<C, D>();
}

しかし、ファクトリ メソッドは次のようにすれば冗長に見えます。

public static void Main()
{
    A<string> first = new A<string>();
    A<int> second = new B<int>();
    A<D> third = new C();
}

更新 2

あなたが本当に欲しいものがこれでない限り:

public abstract class AEnum<T, T3> where T3 : B<T>, new()
{
    private static Func<A<T>> factoryMethod;

    public static readonly Level1 = new AEnum<T>(()=>new A<T>());
    public static readonly Level2 = new AEnum<T>(()=>new B<T>());
    public static readonly Level3 = new AEnum<T>(()=>new T3());

    protected AEnum(Func<A<T>> factoryMethod) { this.factoryMethod = factoryMethod; }

    public A<T> New() { return this.factoryMethod(); }
}

次のように使用します。

public class DEnum : AEnum<D, C>
{
}

と:

public static void Main()
{
    A<D> first = DEnum.Level1.New();
    A<D> second = DEnum.Level2.New();
    A<D> third = DEnum.Level3.New();
}

ただし、上記は に型制約されているため、enum 型を混在させることはできませんD

または、次のようにすることもできます。

public class OpenAEnum<T, T3> : AEnum<T, T3> where T3 : B<T3>
{
}

public class CInt : B<int> {}
public class Cstring : B<string> {}

と:

public static void Main()
{
    A<string> first = OpenAEnum<string, CString>.Level1.New();
    A<int> second = OpenAEnum<int, CInt>.Level2.New();
    A<D> third = OpenAEnum<D, C>.Level3.New();
}

あなたがやろうとしていることは何ですか?

于 2015-08-20T22:19:15.883 に答える