C# 反序列化xml时忽略未知类型

C# 反序列化xml时忽略未知类型,c#,.net,xml-deserialization,C#,.net,Xml Deserialization,我有这个密码: [XmlType( "Metadata" )] [Serializable] public class MetadataContainer : List<MetadataBase> { } [XmlType( "Meta" )] [XmlInclude( typeof( ReadonlyMetadata ) )] [Serializable] public abstract class MetadataBase { } [XmlType( "Readonly" )

我有这个密码:

[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 ) );
    }
}
[XmlType(“元数据”)]
[可序列化]
公共类MetadataContainer:列表
{
}
[XmlType(“Meta”)]
[xmlclude(typeof(ReadonlyMetadata))]
[可序列化]
公共抽象类元数据库
{
}
[XmlType(“只读”)]
[可序列化]
公共类ReadonlyMetadata:元数据库
{
}
[测试夹具]
公共类序列化测试
{
[测试]
public void可以使用已知类型()反序列化
{
常量字符串文本=@“
";
var serializer=新的XmlSerializer(typeof(MetadataContainer));
var metas=(MetadataContainer)序列化程序。反序列化(XmlReader.Create(new StringReader(text));
Assert.That(metas.Count,Is.EqualTo(1));
Assert.That(metas.First(),Is.InstanceOf());
}
[测试]
public void可以反序列化具有未知类型()的
{
常量字符串文本=@“
";
var serializer=新的XmlSerializer(typeof(MetadataContainer));
var metas=(MetadataContainer)序列化程序。反序列化(XmlReader.Create(new StringReader(text));
Assert.That(metas.Count,Is.EqualTo(0));
}
}
第一个测试可以工作,但当我运行第二个测试时,会出现以下错误:

System.InvalidOperationException:XML文档(2,9)中存在错误。 ---->System.InvalidOperationException:无法识别指定的类型:name='Hello',namespace=''',位于


我希望它忽略未识别的类型,而不是出现此错误。有什么方法可以做到这一点吗?

类似问题的通用解决方案:

看一看,看看他们是否解决了问题,或者我们必须变得肮脏。继续读

此问题的有效解决方案

请记住,我不知道您的任务是什么,因为它是将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);
}
[TestMethod]
public void TestLinq2Xml()
{
常量字符串文本=@“
";
//获取元数据库所有实现者的“名称”
var types=AppDomain.CurrentDomain.GetAssemblys().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().First().TypeName);
//创建解析器
var parser=新的XmlSerializer(typeof(MetadataBase));
//创建要填充的metadatacontainer
var metas=新的MetadataContainer();
//用XML中的匹配项填充它
metas.AddRange((从XDocument.Parse(text).substands(“Meta”)中的t开始)
其中types.Contains(t.Attribute(XName.Get)(“type”http://www.w3.org/2001/XMLSchema-instance)(价值)
选择(元数据库)解析器;
//应该有一个人在场
Assert.AreEqual(metas.Count,1);
}

捕获数组中的所有未知元素。您仍然可以使用它们并在以后尝试反序列化,但这允许反序列化完成。在您定义的每个类中,您都需要使用它来反序列化您怀疑存在未知元素的元素

Per:

公共类XClass
'将XmlAnyElementAttribute应用于返回数组的字段
'的XmlElement对象。
公共等位基因()作为XmlElement
端类的XClass

我原以为这会是订阅一个或多个的情况,但在尝试时似乎没有帮助。神秘的。我也认为,结果是非常奇怪的。虽然我没有找到解决方案。否决票是可以的,但请留下反馈帮助我修改我的答案。非常有趣的答案。我必须试一下。
Public Class XClass
    ' Apply the XmlAnyElementAttribute to a field returning an array 
    ' of XmlElement objects.
    <XmlAnyElement()> Public AllElements() As XmlElement
End Class 'XClass