2009-08-06 20 views
1

オブジェクトのインスタンスをキャストし、実際にそのオブジェクトの型にするにはどうすればよいですか?ジェネリックスとXmlSerializerの継承キャストの問題

私は、myClass2とmyClass3の基本クラスであるmyClass1クラスを持っています。 myClass1を監査用に使用したいのですが、myClass1のデータが必要です。 myClass2とmyClass3はmyClass1から継承するため、あなたはmyClass2例のインスタンスにmyClass1のインスタンスを設定することができます。

私はときに、クラスを渡すために、一般的な

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()); 

を使用していますので、問題が来る

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

myClass1 bar = foo; 

私はシリアライズし、XmlSerializerはエラーをスローします。なぜなら、私はそれをmyClass1としてキャストしています。基底のオブジェクトはまだmyClass2です。オブジェクトをキャストして型をチェックし、XmlSerializer getは混乱しています。それをクラス1にしてくださいそれはそれが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; 

名前の値は、メモリ内のデータが実際にはmyClass2であることを示す「myClass2」です。バーの下には、myClass2オブジェクトへのポインタがあります。新しいインスタンスを作成せずに、その新しいインスタンスの値をそのオブジェクトに設定することなく、

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

私は本当にそうしたくありません。

+0

SerializeGenericを呼び出していることを示すことはできますか?また、XMLSterilizerはあなたが望むものではないと思うので、タイトルを変更したいかもしれません。 – SwDevMan81

+0

はいXMLSterilizerはまったく別のものになります –

答えて

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オペレーションを行う単純なリフレクションメソッドを書くとします。 FOO1 & foo2はと、

<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宣言に[XmlInclude(typeof演算(foo2はを))]を追加していない場合Foo2として宣言された型を持つプロパティ...興味深い。

最終1:

私はそれをお勧めしますイムわからないが、これは、動作します。

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> 

を。あなたは継承を持っているとき、XMLシリアル化を行うには

+0

私は既にそれを試していますし、そうすることができますし、同じ理由でエラーになります。このようなジェネリックを使ってserializableObjectの型をTに設定します。 serializableObjectの型を取得するのと同じです。 –

+0

型を明示的に宣言していない場合 –

+0

少なくとも私はこれを理解できない唯一の人ではないので、今は悪くないと感じていません。 –

0

が正しく、ガイドラインのカップルがあります:

  1. は必ず(シリアライズまたはデシリアライズ)typeof(Base)XmlSerializer
  2. を作成する基本クラスにXmlInclude(typeof(Derived))属性を設定します(

これにより、継承階層内の任意のオブジェクトを表すxmlをDeserializeで呼び出すことができます。代替案があります(XmlSerializerのコンストラクタに可能なすべての派生型を渡すなど)があります。