2012-10-29 76 views
1

我遇到了一個問題,試圖遞歸地使用泛型函數進行反序列化算法。我正在從XElement的變量中加載它們的值。但是,如果它們不是原始的,我必須遞歸地在該對象上執行相同的操作。但是,該對象與當前正在處理的對象不是同一類型。因此,例如,如果我有調用通用方法時動態設置<T>

class someObject 
{ 
     otherObject obj = new otherObject(); 
} 

class otherObject 
{ 
    int someInt = 123; 
} 

解串器遞歸地進入另一個對象。然而,問題是我必須動態地改變泛型方法的類型(即,我不知道在編譯時它將會是什麼類型)。該算法如下:

public static T deserialize<T>(XNode element) 
    where T : new() 
{ 
    XElement currentNode = (XElement)element; 

    FieldInfo[] fields = getFields<T>(); 

    T returnValue = new T(); 

    foreach (FieldInfo field in fields) 
    { 
     if (field.FieldType.IsPrimitive) 
     { 
      field.SetValue(returnValue, currentNode.Element(field.Name).Value); 
     } 
     else 
     { 
      //The issue is on the following line 
      field.SetValue(returnValue, deserialize<???>(currentNode.Element(field.Name).Value)); 
     } 
    } 
} 

我已經看到了大量的文檔如何動態地創建類型的列表和對象。但是,我無法找到任何涉及在泛型方法調用中動態切換類型的內容。

任何幫助,非常感謝!讓我知道如果我不清楚...

+5

模板是C++。這些是泛型。 –

+0

謝謝:)編輯標題。 –

+0

所以如果你不知道在編譯時會發生什麼,你的例程在運行時怎麼知道?您的XElement是否具有存儲爲值的類型標誌的屬性? –

回答

1

我會使泛型方法調用另一個私人的非泛型的方法,使用不同的手段來創建實例,而不是new T()。外部泛型方法對方法的調用者來說很方便,所以他們不必投射響應。在內部,你的代碼會更簡單。

請注意,.NET框架的反序列化方法都至少有重載,其取值爲Type而不是泛型類型參數(<T>)。這是你正在發現的原因 - 有時你將類型當作一個對象,然後你不能(明智地)調用一個泛型方法並傳遞該類型參數。

+1

好點,有一個類型參數可能會更直接,並仍然允許遞歸。我養成了在簡單對象上使用新T()的習慣,因爲它縮短了代碼並使其易於閱讀(但它確實強制它們執行())。我認爲你有正確的想法。 –

+0

'Activator.CreateInstance(type)'並不比'new T()'差太多,並且比反射方法好得多。 – recursive

0

試試這個,但你必須與屬性標記類DataContract,數據成員

static readonly XmlWriterSettings ws = new XmlWriterSettings() 
    { 
     OmitXmlDeclaration = true, 
     Encoding = System.Text.Encoding.UTF8 
    }; 


    static XElement ToXElement<T>(T obj) 
    { 
     StringBuilder sb = new StringBuilder(); 
     Type valorType = obj.GetType(); 
     using (var writer = XmlDictionaryWriter.Create(sb, ws)) 
     { 
      DataContractSerializer s = new DataContractSerializer(typeof(T)); 
      s.WriteObject(writer, obj); 
      writer.Flush(); 
      writer.Close(); 
     } 
     return XElement.Parse(sb.ToString()); 
    } 

    static T ToObj<T>(XElement node) 
    { 
     string xml = node.ToString(SaveOptions.DisableFormatting);  
     T respuesta = default(T); 
     DataContractSerializer dcs = new DataContractSerializer(typeof(T)); 
     using (StringReader strReader = new StringReader(xml)) 
     { 
      using (XmlReader xmlReader = new XmlTextReader(strReader)) 
      { 
       respuesta = (T)dcs.ReadObject(xmlReader, false); 
      } 
     } 
     return respuesta; 
    } 

測試:

[DataContract] 
    public class A 
    { 
     [DataMember] 
     public int Prop { get; set; } 
    } 

     var node = ToXElement(12); 
     int obj = ToObj<int>(node); 


     var node2 = ToXElement(new A { Prop = 12 }); 
     A obj2 = ToObj<A>(node2);