簡體   English   中英

使用C#泛型從方法(不是“新”)創建泛型對象

[英]Using C# Generics to create a generic object from a method (not “new”)

我習慣了C ++模板,並意識到在C#中工作原理有些不同。 這就是我想要的:

    T CreateButton<T>() {
       T test = T.create(...some vars...);
       return test;
    }

我以為也許在定義了“創建”方法的基類中使用派生約束可以解決問題,但仍然無法編譯。

我收到此編譯錯誤: **error CS0119: Expression denotes a 'type parameter', where a 'variable', 'value' or 'type' was expected**

有沒有一種方法可以完成我在C#中要做的事情?

您的問題是您正在調用T.Create,就好像它是通用T上的靜態方法一樣。這帶來了兩個問題-首先,您無法繼承靜態變量(必須這樣做才能將T的類型限制為定義“靜態創建”的基本類,以便T.Create進行編譯)。 其次,即使您可以繼承靜態方法,基類.Create()也必須以某種方式“知道”返回T。

您在這里追求的是一家工廠。 定義一個充當T工廠的類,然后您可以編寫

T test = Factory <T> .Create(...一些變量...);

感覺這會導致巨大的switch語句-基於T的真實類型做正確的事情。 但這是控制反轉和依賴注入可以為您提供幫助的地方。 為您需要的每種T類型定義一個帶有“插件”的工廠。 使用IoC將插件注入您的工廠。

這里查看討論

這應該是您所追求的:

class MyFactory<T> where T : new()
{
    public T CreateMyStuff()
    {
        return new T();
    }
}

您必須定義和實現接口(或基類)。 您還必須約束new() 然后,您可以對其使用通用約束。

您不能針對通用參數調用靜態方法。 IE:您無法在T上調用靜態方法。

問題在於特定行T.Create(...)

T是一個Type,而不是變量,因此,除非Create()方法是該類型的靜態方法,否則它將無法編譯,即使T也不知道create的真正含義,因此您將無法編譯函數調用從此開始。 如果以某種方式約束T,以使代碼知道存在Create()函數,則可以執行此操作。

假設T將始終是某個Base類的成員或繼承的成員,則該函數將聲明如下:

T CreateButton<T>() where T : BusinessObjectBase
{
   T test = (T)BusinessObjectBase.create(...some vars...);
   return test;
}

在這種情況下,靜態函數Create()在BusinessObjectBase內部聲明,並且作為T傳入的類型被約束為該類或從該類擴展,從而保證T能夠調用Create()的代碼。功能。

當然,正如其他人提到的那樣,使用new()約束要容易得多。 這使您可以簡單地返回新的T();。 復雜程度要低得多,但是您會丟失create函數中的那些參數。

除了滿足new約束的類型外,沒有任何方法可以創建泛型的新對象,僅提供類型即可。 相反,最好的選擇可能是讓需要創建事物的方法接受適合該任務的委托。

// Suppose you need to be able to create things whose constructors should take
//  an Int32.  Then do something like:

void MakeLotsOfTs<T>(Func<Int32, T> CreationProc) // And whatever other stuff you want
{
  ... whenever you need a new T for a given integer N, call CreationProc(N)
}

如果您有一個Foo類,其構造函數使用Int32 ,並且希望將其傳遞給上述方法,請使用

  MakeLotsOfTs<Foo>( (Int32 param) => new Foo(param) );

Note that this approach will work even if you want to use it with a class whose constructor requires something else (e.g. one could do something like:

MakeLotsOfTs<Bar>( (Int32 param) => new Bar(String.Format("Bar #{0}", param)) );

與能夠指定“參數化” new約束相比,此方法對調用者的工作量更多,但是功能更強大。

暫無
暫無

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

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