7

私はこのコードを持っています:

[XmlType( "Metadata" )]
[Serializable]
public class MetadataContainer : List<MetadataBase>
{
}

[XmlType( "Meta" )]
[XmlInclude( typeof( ReadonlyMetadata ) )]
[Serializable]
public abstract class MetadataBase
{
}

[XmlType( "Readonly" )]
[Serializable]
public class ReadonlyMetadata : MetadataBase
{
}

[TestFixture]
public class SerializationTests
{
    [Test]
    public void Can_deserialize_with_known_type()
    {
        const string text = @"<Metadata xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">
                        <Meta xsi:type=""Readonly"" />
                    </Metadata>";

        var serializer = new XmlSerializer( typeof( MetadataContainer ) );
        var metas = (MetadataContainer)serializer.Deserialize( XmlReader.Create( new StringReader( text ) ) );

        Assert.That( metas.Count, Is.EqualTo( 1 ) );
        Assert.That( metas.First(), Is.InstanceOf<ReadonlyMetadata>() );
    }

    [Test]
    public void Can_deserialize_with_unknown_type()
    {
        const string text = @"<Metadata xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">
                        <Meta xsi:type=""Hello"" />
                    </Metadata>";

        var serializer = new XmlSerializer( typeof( MetadataContainer ) );
        var metas = (MetadataContainer)serializer.Deserialize( XmlReader.Create( new StringReader( text ) ) );

        Assert.That( metas.Count, Is.EqualTo( 0 ) );
    }
}

最初のテストは機能しますが、2 番目のテストを実行すると、次のエラーが発生します。

System.InvalidOperationException : XML ドキュメントにエラーがあります (2、9)。----> System.InvalidOperationException : 指定された型が認識されませんでした: name='Hello', namespace='', at .

このエラーが発生する代わりに、認識されていない型を無視したいと思います。これを行う方法はありますか?

4

2 に答える 2

3

同様の問題の一般的な解決策:

未知の要素のイベント (リンク)未知の属性のイベント (リンク)を見て、それらが問題を解決するかどうかを確認してください。読む...

この問題の実用的な解決策

私はあなたの仕事が何であるか分からないことに注意してください.AFAIKはxmlをデータ構造にシリアライズしています. データ構造を変更できる場合は、Linq2XML を見て、目的に合ったスマート ファクトリを作成することをお勧めします。

[TestMethod]
public void TestLinq2Xml()
{
  const string text = @"<Metadata xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">
                            <Meta xsi:type=""Readonly"" />
                            <Meta xsi:type=""Garbage"" />
                      </Metadata>";

  // Get the "names" of all implementors of MetadataBase
  var types = AppDomain.CurrentDomain.GetAssemblies().ToList()
     .SelectMany(s => s.GetTypes())
         .Where(p => typeof(MetadataBase).IsAssignableFrom(p) && !p.IsAbstract && !p.IsInterface)
         .Where(t => t.GetCustomAttributes(typeof(XmlTypeAttribute), false).Any())
         .Select(t => t.GetCustomAttributes(typeof(XmlTypeAttribute), false)
             .Cast<XmlTypeAttribute>().First().TypeName);

  // Create a parser
  var parser = new XmlSerializer(typeof(MetadataBase));

  // Create metadatacontainer to fill
  var metas = new MetadataContainer();
  // Fill it with matching from from the XML
  metas.AddRange((from t in XDocument.Parse(text).Descendants("Meta")
                where types.Contains(t.Attribute(XName.Get("type", "http://www.w3.org/2001/XMLSchema-instance")).Value)
                select (MetadataBase)parser.Deserialize(t.CreateReader())).ToList());

  // Should be one guy present
  Assert.AreEqual(metas.Count, 1);
}
于 2012-10-31T07:50:25.490 に答える
0

配列内のすべての不明な要素をキャッチします。それらを使用して後で逆シリアル化を試みることはできますが、これにより逆シリアル化が完了します。不明な要素があると思われる要素を逆シリアル化するために、定義する各クラスでこれが必要になります。

http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlanyelementattribute.aspxごと:

Public Class XClass
    ' Apply the XmlAnyElementAttribute to a field returning an array 
    ' of XmlElement objects.
    <XmlAnyElement()> Public AllElements() As XmlElement
End Class 'XClass
于 2014-07-15T12:37:52.063 に答える