简体   繁体   English

如何动态添加XmlInclude属性

[英]How to add XmlInclude attribute dynamically

I have the following classes 我有以下课程

[XmlRoot]
public class AList
{
   public List<B> ListOfBs {get; set;}
}

public class B
{
   public string BaseProperty {get; set;}
}

public class C : B
{
    public string SomeProperty {get; set;}
}

public class Main
{
    public static void Main(string[] args)
    {
        var aList = new AList();
        aList.ListOfBs = new List<B>();
        var c = new C { BaseProperty = "Base", SomeProperty = "Some" };
        aList.ListOfBs.Add(c);

        var type = typeof (AList);
        var serializer = new XmlSerializer(type);
        TextWriter w = new StringWriter();
        serializer.Serialize(w, aList);
    }    
}

Now when I try to run the code I got an InvalidOperationException at last line saying that 现在当我尝试运行代码时,我在最后一行得到了一个InvalidOperationException

The type XmlTest.C was not expected. XmlTest.C类型不是预期的。 Use the XmlInclude or SoapInclude attribute to specify types that are not known statically. 使用XmlInclude或SoapInclude属性指定静态未知的类型。

I know that adding a [XmlInclude(typeof(C))] attribute with [XmlRoot] would solve the problem. 我知道用[XmlRoot]添加[XmlInclude(typeof(C))]属性可以解决问题。 But I want to achieve it dynamically. 但我想动态地实现它。 Because in my project class C is not known prior to loading. 因为在我的项目中,C类在加载之前是未知的。 Class C is being loaded as a plugin, so it is not possible for me to add XmlInclude attribute there. C类正在作为插件加载,因此我无法在那里添加XmlInclude属性。

I tried also with 我也尝试过

TypeDescriptor.AddAttributes(typeof(AList), new[] { new XmlIncludeAttribute(c.GetType()) });

before 之前

var type = typeof (AList);

but no use. 但没用 It is still giving the same exception. 它仍然提供相同的例外。

Does any one have any idea on how to achieve it? 有没有人知道如何实现它?

Two options; 两种选择; the simplest (but giving odd xml) is: 最简单的(但给出奇怪的xml)是:

XmlSerializer ser = new XmlSerializer(typeof(AList),
    new Type[] {typeof(B), typeof(C)});

With example output: 使用示例输出:

<AList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <ListOfBs>
    <B />
    <B xsi:type="C" />
  </ListOfBs>
</AList>

The more elegant is: 更优雅的是:

XmlAttributeOverrides aor = new XmlAttributeOverrides();
XmlAttributes listAttribs = new XmlAttributes();
listAttribs.XmlElements.Add(new XmlElementAttribute("b", typeof(B)));
listAttribs.XmlElements.Add(new XmlElementAttribute("c", typeof(C)));
aor.Add(typeof(AList), "ListOfBs", listAttribs);

XmlSerializer ser = new XmlSerializer(typeof(AList), aor);

With example output: 使用示例输出:

<AList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <b />
  <c />
</AList>

In either case you must cache and re-use the ser instance; 在任何一种情况下,您都必须缓存并重新使用ser实例; otherwise you will haemorrhage memory from dynamic compilation. 否则你会从动态编译中出血。

Building on Marc's first answer (I only have to read, so I don't need to prevent the weird output), I use a more dynamic/generic type-array to account for unknown types, inspired by this codeproject . 在马克的第一个答案大楼(我只需要读,所以我并不需要防止怪异输出),我使用了一个更加动态/通用型阵列占未知类型,受此启发CodeProject上

    public static XmlSerializer GetSerializer()
    {
        var lListOfBs = (from lAssembly in AppDomain.CurrentDomain.GetAssemblies()
                           from lType in lAssembly.GetTypes()
                           where typeof(B).IsAssignableFrom(lType)
                           select lType).ToArray();
        return new XmlSerializer(typeof(AList), lListOfBs);
    }

(One could probably make it more efficient, eg using a static or read-only type-array in stead of a local variable. That would avoid repeatedly using Reflection. But I don't know enough about when assemblies get loaded and classes and properties get initialized, to know if that would get you into trouble. My usage is not that much, to take the time to investigate this all, so I just use the same Reflection multiple times.) (人们可能会提高它的效率,例如使用静态或只读类型数组而不是局部变量。这样可以避免重复使用Reflection。但是我不知道何时加载程序集以及类和属性初始化,知道是否会让你遇到麻烦。我的用法并不多,花时间去研究这一切,所以我只是多次使用相同的Reflection。)

Have a look at the documentation of XmlSerializer. 看一下XmlSerializer的文档。 There is a constructor which expects known types as the second parameter. 有一个构造函数需要将已知类型作为第二个参数。 That should work fine for you use case. 这应该适用于你的用例。

我不认为属性可以在运行时应用,因为它们用于在CIL代码中创建元数据。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用XmlInclude动态指定类型? - How to use XmlInclude to specify types dynamically? XmlInclude属性和派生类 - XmlInclude attribute and derived classes 如何使用XmlInclude序列化IEnumerable - How to use XmlInclude to serialize IEnumerable 调用Web服务时出现问题-使用XmlInclude或SoapInclude属性 - Issue calling a web service - Use the XmlInclude or SoapInclude attribute 动态将属性添加到属性 - Add Attribute to the property dynamically 使用 XmlInclude 或 SoapInclude 属性指定静态未知的类型 - Use the XmlInclude or SoapInclude attribute to specify types that are not known statically 如何在从具有工作“XmlInclude”属性的基类继承的类中包含“XmlInclude”? - How do I include “XmlInclude” on a Class that inherits from a base class with working “XmlInclude” attributes? 如何在没有属性构造函数的情况下向属性添加动态添加的属性值(Reflection.Emit) - How to add values to attribute added dynamically to property without attribute constructor(Reflection.Emit) “不希望使用RoleProxy类型。 使用XmlInclude或SoapInclude属性可以指定静态未知的类型。” NHibernate - “The type RoleProxy was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.” NHibernate xxx类型不是预期的。 使用XmlInclude或SoapInclude属性来指定静态未知的类型 - The type xxx was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM