簡體   English   中英

C#工廠的通用繼承

[英]C# Factory for generic inheritance

對於這個基本問題,我深表歉意,但是我找不到任何文檔。 也許是因為我不知道正確的術語。

類結構:

class D{}

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

我嘗試創建一個返回C的工廠方法,而總返回類型必須為A。不幸的是,此實現將產生一個編譯時錯誤,盡管繼承結構似乎是協變的。

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

更具體地說,我試圖建立一個工廠,該工廠能夠根據輸入值生成所有三個類,而必須獲得通用功能。

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():
}

更新

我必須創建三個對象,如下所示。

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

在包含FactoryMethod的類的范圍內, T是沒有意義的。 您需要指定A的通用參數才能將其用作類型。

在這種情況下,由於CB<D> ,而B<D>A<D> ,那么您將使用A<D>作為返回類型。

對於第二個問題,如果使工廠方法通用,我想您可以得到想要的。

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);
    }
}

因為CA<D> )不可分配給某些A<T> (編譯器不知道當TD時總是會傳遞3 ),所以這不是類型安全的。

C是綁定類型A<D>的子類。 因此,以下內容是有效的:

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

因為我們可以肯定地說CA<D> 但是C不是通用類型,並且不能轉換為開放類型A<T> ,其中T是通用參數,因為T可以是任何類型。

但是,以下內容有效:

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

由於B<T>也是開放的泛型類型,並且任何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!

鑒於這種:

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不能抽象,因為您正在嘗試構造它。

但是,由於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();
}

但是您不能混合枚舉類型,因為上面的類型被限制為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();
}

您正在嘗試做什么?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM