簡體   English   中英

C#通用工廠方法

[英]C# generic factory method

也許這是一個簡單的C#新手問題,但是就這樣吧-與我的其他問題相比,這是一個全新的突破。其他問題是如此的困難,以至於沒人知道答案。 :)

假設我在C#中有一個泛型類型:

Thing<T>

假設我想使用靜態工廠方法制作東西。 在Java中,這沒有問題:

public static <T> Thing<T> createThing()
{
  return flag ? new Thing<Integer>(5) : new Thing<String>("hello");
}

如何在C#中執行此操作? 謝謝。

如果要使用許多不同的模板參數之一返回模板化類的實例,則一種實現方法是使用抽象基(或接口):

abstract class UntypedThing { }
class Thing<T> : UntypedThing
{
    public Thing(T t) { }
}

class Foo
{
    public static UntypedThing createThing(bool flag)
    {
        if (flag)
            return new Thing<int>(5);
        else return new Thing<String>("hello");
    }
}

UntypedThing類將包含盡可能多的不依賴模板類型的代碼。 理想情況下, Thing類將僅包含依賴於模板類型的代碼。 工廠類Foo始終返回前者。

從理論上講,您可以使用反射來構建正確的泛型類型,但是對於您來說這將是毫無用處的,因為有時您需要將其轉換為不太具體的類型。

public class ThingFactory  {
    public object Create(bool flag) {
        Type outputType = null;
        if(flag) {
            outputType = typeof(string);
        } else {
            outputType = typeof(int);
        }
        return Activator.CreateInstance(typeof(Thing<>).MakeGenericType(outputType));
    }
}

如您所見,這樣做的價值大約為零,因為您需要將返回類型強制轉換為所需的類型,這意味着確定返回類型的邏輯必須位於Create方法之外。

我將使用Reinderien的方法,並且具有非通用基礎。 這是最理智和慣用的方法。

哦,當我只是嘗試做一些簡單的事情時,我就會陷入麻煩。

事實證明, C#4允許這種協方差 首先,我必須將Thing用作接口並指定“ out”通用參數:

public interface Thing<out T> {...}

但是,如果我做某些事情,C#將不允許我使用協方差。 例如,如果我嘗試從接口返回T:

public interface Thing<out T>
{
  public T GetT();

即使我設法與Thing保持協方差,我該怎么辦?

Thing<object> thing=createThing();

編譯器告訴我,不能從使用情況推斷類型。

假設我說擰整個T東西並使工廠方法返回類型為對象的Thing:

public static Thing<object> createThing() {...}

很好,但是現在放在哪里?

IList<Thing<object>> list=new List<Thing<object>>();
Thing<object> thing=createThing();
list.Add(thing);

是的,我不得不說這是對象類型為T的Thing列表,因為C#沒有通配符類型。

如果這是Java,我會簡單地說:

public class Thing<T> {...}

public static <T> Thing<T> createThing() {...}

List<?> things=new ArrayList<Thing<?>>();
Thing<?> thing=createThing();
things.add(thing);

如果我想通過說T必須是特殊類型來提高安全性,我會說:

public static <T extends MyBaseType> Thing<T> createThing() {...}

List<? extends MyBaseType> things=new ArrayList<Thing<? extends MyBaseType>>();
Thing<? extends MyBaseType> thing=createThing();
things.add(thing);

然后,當我獲得更多信息時,我便想出了T是什么。

這一切似乎都歸結為C#中不完整的泛型協方差以及缺少C#泛型通配符。 (我仍然認為這不是擦除問題。)

那我該怎么辦? 唯一要做的簡單事情似乎是遵循Reinderien的回答並拆分出一個非泛型基類。

(我想知道在這個非泛型基類中是否可以有對象getValue(),然后在子類中使用協方差返回T getValue()?哎呀,我對此感到厭倦了-我將其留給另一個天。)

暫無
暫無

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

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