2009-08-06 52 views
1

如何投射對象的實例並將其實際製作爲該類型的對象?泛型和XmlSerializer的繼承性投射問題

我有一個類myClass1,它是myClass2和myClass3的基類。我想使用myClass1進行審計,審計所有我想要的是myClass1中的數據。由於myClass2和myClass3從MyClass1的繼承您可以MyClass1的實例設置爲myClass2例子的一個實例:

myClass2 foo = new myClass2(); 
foo.prop1 = "some data"; 
foo.prop2 = "some More Data"; 

myClass1 bar = foo; 

的問題來了,因爲我使用的是通用的

public static IXPathNavigable SerializeGeneric<T>(T serializableObject) 
    { 
     String XmlizedString = "Error processing request"; 
     XmlDocument XMLObject = new XmlDocument(); 
     try 
     { 
      MemoryStream memoryStream = new MemoryStream(); 
      XmlSerializer xs = new XmlSerializer(serializableObject.GetType()); 

傳遞上課的時候我序列化它和XmlSerializer拋出一個錯誤,因爲即使我已經把它轉換爲myClass1,但底層對象仍然是一個myClass2,你可以通過將它轉換爲一個對象然後檢查類型和XmlSerializer得到困惑,因爲我告訴它讓它成爲class1雖然它是自己的反射,它將它視爲一個myClass2

myClass2 foo = new myClass2(); 
foo.prop1 = "some data"; 
foo.prop2 = "some More Data"; 

myClass1 bar = foo; 
object obj = bar; 
string name = obj.GetType().Name; 

name的值是「myClass2」,它有意義地看到內存中的數據實際上是一個myClass2,下面的條只是一個指向myClass2對象的指針。不創建新實例並將該新實例的值設置爲該對象,如

myClass1 bar = new myClass1(){prop1=foo.prop1, prop2=foo.prop2}; 

我真的不想這樣做。

+0

你能告訴你正在調用SerializeGeneric嗎?另外,您可能想更改標題,因爲我不認爲XMLSterilizer是您想要的。 – SwDevMan81 2009-08-06 16:44:43

+0

是的XMLSterilizer會是完全不同的東西 – 2009-08-06 16:48:57

回答

1

不知道這是否會工作,但嘗試將其更改爲:

XmlSerializer xs = new XmlSerializer(typeof(T)); 

這將告訴串行創建您指定的任何類型的序列化實例。雖然我不確定序列化程序是否會執行此操作。

編輯:只要你撥打

SerializeGeneric<MyClass1>(foo); 

再次編輯:

這個剛剛試了一下:

public void Test() 
    { 
     var obj = new Foo2() { Prop1 = "Test", Prop2 = "Test2" }; 

     SerializeGeneric((Foo1)obj); 
    } 

    private void SerializeGeneric<T>(T obj) 
    { 
     StringWriter writer = new StringWriter();  
     XmlSerializer xs = new XmlSerializer(typeof(T)); 
     xs.Serialize(writer, obj); 

     Console.WriteLine(writer.ToString()); 
    } 


    public class Foo1 
    { 
     public string Prop1 { get; set; } 
    } 

    public class Foo2 : Foo1 
    { 
     public string Prop2 { get; set; } 
    } 

它拋出的 「意外型」 的異常。事實證明,序列化程序不會將對象序列化爲不同的類型。不知道有什麼辦法可以做到。

我想你可以編寫一個自定義的序列化程序,或者編寫一個簡單的反射方法,該方法執行僅從您想要的foo1複製屬性的memberwiseclone-ish操作。

有趣的是它並沒有錯誤,如果你添加[XmlInclude(typeof運算(foo2的))]將Foo1聲明,雖然它輸出該廢話

<Foo1 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="Foo2"> 
    <Prop1>Test</Prop1> 
    <Prop2>Test2</Prop2> 
</Foo1> 

這是一個Foo1聲明,與Foo1 & foo2的屬性,聲明爲Foo2的類型......有趣。

最後一個:

這工作,但我不確定我會推薦它。

public void Test() 
    { 
     var obj = new Foo2() { Prop1 = "Test", Prop2 = "Test2" }; 

     SerializeGeneric(ShallowCopy<Foo1>(obj)); 
    } 

    private T ShallowCopy<T>(object input) 
     where T : class, new() 
    { 
     T newObj = Activator.CreateInstance<T>(); 
     Type oldType = input.GetType(); 
     BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetField | BindingFlags.SetField; 
     var oldProperties = oldType.GetProperties(flags); 

     foreach (var pd in typeof(T).GetProperties(flags)) 
     { 
      var oldPd = oldProperties.FirstOrDefault(x=>x.Name == pd.Name && x.PropertyType == pd.PropertyType); 

      if(oldPd != null) 
       pd.SetValue(newObj, oldPd.GetValue(input, null), null); 
     } 

     return newObj; 
    } 

這給了你:

<Foo1 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <Prop1>Test</Prop1> 
</Foo1> 

這看起來很完美。

+0

我已經嘗試過,是的,你可以做到這一點,它出於同樣的原因,通過使用這樣的泛型它將serializableObject的類型設置爲T,所以gettig類型的T是與獲取SerializableObject類型相同, – 2009-08-06 17:01:18

+0

如果顯式聲明類型,則不適用。 – 2009-08-06 17:02:37

+0

至少我現在不覺得那麼糟糕,我不是唯一一個不知道這個的人 – 2009-08-06 17:19:39

0

要做到XML序列化正確時,你有繼承,有幾個原則:

  1. 始終創建XmlSerializertypeof(Base)(序列化時或反序列化)
  2. 設置在基類中的XmlInclude(typeof(Derived))屬性(每一個派生類)

這使您可以撥打反序列化表示在繼承層次中的任何對象的任何XML。還有其他的選擇(比如將所有可能的派生類型傳遞給XmlSerializer的構造函數,但是如果這是對屬性的改進,那麼它的值得商榷)