2011-04-12 238 views
1

我寫了一個泛型類,並希望從靜態方法中創建它的實例。問題是我無法創建對象的通用實例。我知道這聽起來很混亂,最好是展示代碼。泛型類型的返回實例

public class Parameter<T> : IParameter<T> 
{ 
    public string Name { get; set; } 
    public T Value { get; set; } 

    public bool IsValid() 
    { 
     if (String.IsNullOrEmpty(Name)) 
      return false; 

     return (typeof(T) == typeof(String)) || 
       typeof(T) == typeof(bool) || 
       typeof(T) == typeof(int) || 
       typeof(T) == typeof(double); 
    } 

    public XElement ToXml() 
    { 
     if (!IsValid()) 
      throw new InvalidParameterException(); 

     var xElement = new XElement("Parameter", Value, 
            new XAttribute("Type", typeof (T)), 
            new XAttribute("Name", Name)); 
     return xElement; 
    } 

    public static Parameter<T> FromXml(XElement xElement) 
    { 
     var sType = xElement.Attributes() 
        .Where(attribute => attribute.Name == "Type") 
        .Single().Name.ToString(); 
     var name = xElement.Attributes() 
           .Where(attribute => attribute.Name == "Name") 
           .Single().Name.ToString(); 
     var sValue = xElement.Value;//need to use this 
     var typeVar = Type.GetType(sType);// and this to create proper instance of Parameter<T> 

     //I need somehow set T equal to typeVar here and Set 
     return new Parameter<T>() {Name = name};//this is wrong. 
     //I need return either Parameter<int> or Paramter<double> or Parameter<string> or Parameter<bool> 
     //basing on typeVar 
    } 
} 

我不確定這是否有可能...但看起來像它是微不足道的對象設計要求。有任何想法嗎? 謝謝!

UPD:我正在使用.NET 4.0。它有什麼區別? :)

UPD2:現在看問題,我看到這是一個愚蠢的問題。並且返回這樣的「通用」對象是不可能的。

+0

這是完全不可能從方法內部設置'T'。想想:你怎麼可能稱這種方法? – SLaks 2011-04-12 16:30:29

+0

var parameter = Parameter.FromXml(element); ? :) – 2011-04-12 16:38:22

+0

ofcourse你可以潛入動態領域,但我不會潛入那一個快速;) – Polity 2011-04-12 16:41:06

回答

1

創建一個非泛型基類,並從中繼承泛型類(它們可以具有相同的名稱,只有泛型類型不同)。在非泛型基類上,在靜態方法中創建泛型實例(它返回非泛型基類作爲結果)。然後,您可以將其轉換爲您期望的泛型類型。

public abstract class Parameter { 
    public static Parameter FromXml(XElement xElement) { 
    ... 
    } 

    public string Name { get; set; } 

    public abstract XElement ToXml(); 
} 

public class Parameter<T>: Parameter { 
    public T Value { get; set; } 

    public override XElement ToXml() { 
    ... 
    } 
} 

是不是真的這樣做,因爲你的樣品中被指定T類型的靜態方法運行前的另一種方式。

+0

謝謝!我想過這個。鑑於我在使用.NET 4.0,你確定沒有其他方法嗎? – 2011-04-12 16:37:15

+0

是的,因爲這會違反合約,無論使用哪個版本:在您的代碼中,參數 .FromXml()*必須*返回一個參數,因爲這是該方法的聲明返回類型。 – Lucero 2011-04-12 16:39:04

0

這可以爲自定義類工作,但它可能不適用於值類型。看看This Post看看這個工作對於堆類型。

+0

這與這個問題真的有關係嗎? – Lucero 2011-04-12 16:40:20

0

正如SLak所示,這是不可能的。它認爲這種方式,

Parameter<???> value = Parameter<???>.FromXml(...); 

你以後還怎麼解決時,它依賴於的XmlElement的內容questionmarks應該是什麼?

您應該使用一個公共類,它既捕獲Value作爲對象並公開類型信息。

1

問題是:T是在編譯時評估的。編譯器沒有任何機會知道你的'Type'將在運行時評估哪個實際類型。另外,在編譯的程序集中,不再存在泛型。因此,爲了在運行時構建一個類型,根據只能在運行時進行評估的條件,您必須將編譯器作爲具體類型進行編譯。所以,地方您可以在一個if ...這樣的其他梯級決定你的返回類型:

if (sType is String) 
    return new Parameter<String>() 

else if (sType is double) 
    return new Parameter<double>() 
... 

這可以被放置在工廠類的內部或向右附近XElement類,我猜。 爲了能夠返回參數,例如,您可以使用一個接口(或者一個普通的基類,就像在另一個答案中一樣),它可以代表所有參數變體。這就是爲什麼解析Xml IMO的方法更好地放置在Parameter之外的原因。

而且,因爲它似乎,你是從證書XML「反序列化」的,可以考慮使用一些去/串行功能;)

+0

「另外,在編譯後的程序集中,不再存在泛型。」 - 我認爲你正在將Java的刪除與.NET(真正的)泛型混合在一起。在.NET中,每個泛型類型爲用作類型參數的每個泛型類型組合形成一個不同的類型。你可以在運行時使用開放的泛型'Type'上的'MakeGenericType()'(例如在這個樣例中'typeof(Parameter <>)。MakeGenericType(typeof(string))''在運行時產生與' typeof(參數)')。 – Lucero 2011-04-13 08:42:03