2012-10-30 56 views
1

我想將一個對象傳遞給xml反序列化的結果類型並保持強大的輸入。使用xml反序列化的泛型

因此,反序列化類可以採用任何實現IResult接口的類型,在本例中爲Result和Result2。

我得到了這個工作,使getObject方法返回動態,但我寧願保持編譯時檢查,我認爲它應該是可能的。

我試過使用泛型,如下面的例子,但是deser.getObject(doc());行給我一個「不能從使用推斷」編譯錯誤。

感謝您的幫助。

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.Text; 
using System.Xml; 
using System.Xml.Serialization; 

namespace SOQuestion 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 

      var deser = new Deserialised(new Result()); 
      var result = deser.getObject(doc()); 

      var deser2 = new Deserialised(new Result2()); 
      var result2 = deser.getObject(doc()); 

      Console.Writeline(result.status); 
      Console.Writeline(result2.status); 
     } 

     public XmlDocument doc() 
     { 
      var doc = new XmlDocument(); 
      var el = (XmlElement)doc.AppendChild(doc.CreateElement("Result")); 
      el.SetAttribute("status", "ok"); 
      el.SetAttribute("status2", "not ok"); 
      return doc; 

     } 

    } 

    class Deserialised 
    { 

     private IResult result; 
     private Type resultType; 

     public Deserialised(IResult _result) 
     { 
      result = _result; 
      resultType = Type.GetType(result.GetType().AssemblyQualifiedName); 
     } 


     public T getObject<T>(XmlDocument xml) 
     { 
      var mySerializer = new XmlSerializer(resultType); 
      var myStream = new MemoryStream(); 
      xml.Save(myStream); 
      myStream.Position = 0; 
      var r = mySerializer.Deserialize(myStream); 
      return (T)r; 
     } 

    } 

    interface IResult 
    { 
     public string status {get;set;} 
    } 



    [Serializable] 
    public class Result :IResult 
    { 
     [XmlAttribute] 
     public string status { get; set; } 
    } 

    [Serializable] 
    public class Result2 : IResult 
    { 
     [XmlAttribute] 
     public string status2 { get; set; } 
    } 
} 
+1

你認爲應該從哪裏得到''?如果你手動操作,你會怎麼知道'T'? –

回答

-1

所以我找到了一個解決方案,我的兩個要求1.傳入類型實現IResult接口2.返回的對象是靜態類型。 泛型方法與約束類似下面

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.Text; 
using System.Xml; 
using System.Xml.Serialization; 

namespace SOQuestion 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 

      var result = new Deserialised().getObject<Result>(); 

      var result2 = new Deserialised().getObject<Result2>(); 

      Console.WriteLine(result.status); 
      Console.WriteLine(result.errorMessage); 
      Console.ReadLine(); 


     } 
    } 

    class Deserialised 
    { 

     public T getObject<T>() where T : IResult 
     { 
      try 
      { 
       var instance = Activator.CreateInstance<T>(); 
       var mySerializer = new XmlSerializer(instance.GetType()); 
       var myStream = new MemoryStream(); 
       doc().Save(myStream); 
       myStream.Position = 0; 
       var r = mySerializer.Deserialize(myStream); 
       throw new DivideByZeroException(); 
       return (T)r; 
      } 

      catch (Exception exp) 
      { 
       var instance = Activator.CreateInstance<T>(); 
       instance.errorMessage = "something wrong here"; 
       return instance; 
      } 
      ; 
     } 

    public static XmlDocument doc() 
     { 
      var doc = new XmlDocument(); 
      var el = (XmlElement)doc.AppendChild(doc.CreateElement("Result")); 
      el.SetAttribute("status", "ok"); 
      el.SetAttribute("status2", "notok"); 
      return doc; 

     } 

    } 

    interface IResult 
    { 
     string status { get; set; } 
     string errorMessage { get; set; } 
    } 

    [Serializable] 
    public class Result : IResult 
    { 
     [XmlAttribute] 
     public string status { get; set; } 

     [XmlAttribute] 
     public string errorMessage { get; set; } 

     [XmlAttribute] 
     public string message { get; set; } 
    } 

    [Serializable] 
    public class Result2 : IResult 
    { 
     [XmlAttribute] 
     public string status { get; set; } 

     [XmlAttribute] 
     public string message2 { get; set; } 

     [XmlAttribute] 
     public string errorMessage { get; set; } 
    } 

    [Serializable] 
    public class Result3 
    { 
     [XmlAttribute] 
     public string status { get; set; } 

     [XmlAttribute] 
     public string message2 { get; set; } 

     [XmlAttribute] 
     public string errorMessage { get; set; } 
    } 
} 
+0

你使用'Activator.CreateInstance ();'只是爲了調用'GetType()'嗎?只需使用'typeof(T)'。 –

+0

...什麼是'DivideByZeroException'?你總是會以這種方式返回_「這裏出現了問題」。 –

+0

除以零在測試中的catch塊 – Jules

1

事實上,這是不會工作 - 編譯器無法知道從該T的方式。請記住,T來自調用者在編譯時,而不是來自運行時方法的結果。有反射/泛型之間切換的方式,但它是醜陋的,在這裏不會有太大的幫助。我只想回到object代替:

public object GetObject(XmlDocument xml) { 
    var mySerializer = new XmlSerializer(resultType); 
    using(var myStream = new MemoryStream()) { 
     xml.Save(myStream); 
     myStream.Position = 0; 
     return mySerializer.Deserialize(myStream); 
    } 
} 

,然後讓調用處理dynamic等:

var deser = new Deserialised(new Result()); 
dynamic result = deser.GetObject(doc()); 

var deser2 = new Deserialised(new Result2()); 
dynamic result2 = deser.GetObject(doc()); 

Console.Writeline(result.status); 
Console.Writeline(result2.status); 

由於上述dynamic中,.status兩個Console.WriteLine仍然可以工作。

+0

但是這沒有幫助,因爲我想在調用方法中編譯時間檢查。而且,反序列化的類在編譯時會知道該類型,因爲它傳遞給構造函數,然後用於在XmlSerialiser中設置resultType變量。如果我將Result對象作爲通用參數傳入getObject而不是從私有字段中獲取,它會改變什麼嗎? – Jules

+0

@Jules是的,這會給它一些推斷來自'T'的東西,但傳入的實例會(我懷疑)是完全多餘的,因爲序列化器將創建實際實例。 –

0

在我看來the answer you provided yourself overcomplicates事情。 (除了做一些其他奇怪的東西,...看到我的意見。)

在這裏使用泛型沒有任何好處。您也可以使用以下方法,並且您的兩項要求仍然適用。

public IResult GetObject(XmlDocument xml) 
{ 
    var mySerializer = new XmlSerializer(resultType); 
    using (var myStream = new MemoryStream()) 
    { 
     xml.Save(myStream); 
     myStream.Position = 0; 
     return (IResult)mySerializer.Deserialize(myStream); 
    } 
} 

...簡單地調用它,如下所示:

var deser = new Deserialised(new Result()); 
var result = (Result)deser.getObject(doc()); 

var deser2 = new Deserialised(new Result2()); 
var result2 = (Result2)deser.getObject(doc()); 

投射到任何不執行IResult會引發一個編譯錯誤。


這是不是真的清楚你正在嘗試做的,但假設你做Deserialised通用。

class Deserialised<T> 
    where T : IResult 
{ 

    private T result; 
    private Type resultType; 

    public Deserialised(T _result) 
    { 
     result = _result; 
    } 


    public T getObject(XmlDocument xml) 
    { 
     var mySerializer = new XmlSerializer(typeof(T)); 
     var myStream = new MemoryStream(); 
     xml.Save(myStream); 
     myStream.Position = 0; 
     var r = (T)mySerializer.Deserialize(myStream); 
     return r; 
    } 

} 

爲什麼你甚至會通過_result作爲參數並存儲它?我的猜測是你只需要它,因爲你不知道typeof()?在這種情況下,簡單地刪除它。再次這樣做後,您最終會得到一個定義您的泛型參數的類,同時再次定義所需演員的唯一目的。

+0

是的,當Deserialised類應該能夠從構造函數參數中知道所需的類型時,您必須投射結果似乎有點難看。任何想法如何我可以刪除這個演員? – Jules

+0

@Jules稍後會有一些註釋,但首先是關於演員的醜陋之處,而不是指定一個通用參數?這個泛型爲你做的唯一事情就是在方法內部而不是外部進行。關於它本質上沒有什麼「通用的」,因此我發現使用通用的方法根本不會更清楚。這是相同數量的代碼。 –

+0

您確實有一點,並且您似乎只想爲'IResult'對象使用'Deserialised'類,您可以輕鬆地創建'Deserialised'通用屬性。我會更新我的答案。 –