这是我要解决的问题:我有一个多媒体节目的插件结构,它允许通过从我的框架中的基类进行子类化来在外部程序集中实现媒体类型。节目包含媒体类型列表。使用 XmlSerializer
以 XML 形式加载和保存节目。即使使用插件 MediaTypes 的编程类型映射,这一切都有效。
但是,我希望能够加载包含未知媒体类型的 XML 文件,因为该插件不可用。
为了便于说明,这里有一个 XML 文件:
<MultiMediaShow>
<MediaTypes>
<SomeType />
<SomeType />
<AnotherType />
<UnknownTypeFromPluginNotLoaded />
</MediaTypes>
</MultiMediaShow>
在上面的示例中,我假设 2 个“已知”MediaTypes SomeType
和 AnotherType
,来自 2 个插件程序集。第三种类型 (UnknownTypeFromPluginNotLoaded
) 未知。
我已经能够反序列化此类未知对象,但在序列化方面遇到了困难。在我的应用程序中,到目前为止我有以下代码:
// To be implemented / subclassed by plugin assembly types
public abstract class MediaType
{
}
public class UnknownMediaType : MediaType
{
[XmlAnyElement]
public XmlElement[] UnknownChildElements;
[XmlAnyAttribute]
public XmlAttibute[] UnknownAttributes;
[XmlIgnore]
public string XmlTagName; // stores the xml element tag name in the original document
}
[XmlRoot("MultimediaShow")]
public class MultimediaShow
{
public List<MediaType> MediaTypes = new List<MediaType>();
}
当使用 XmlSerializer
反序列化时,我使用事件 UnknownElement
并手动将 UnknownMediaType
元素插入 show.MediaTypes
:
void HandleUnknownElements(Show show, List<XmlElementEventArgs> unknownElementEvents, XmlAttributeOverrides overrides)
{
// add a root attribute to UnknownMediaType
XmlAttributes attrs = new XmlAttributes();
XmlRootAttribute xmlRoot = new XmlRootAttribute(e.Element.Name);
attrs.XmlRoot = xmlRoot;
XmlAttributeOverrides o = new XmlAttributeOverrides();
o.Add(typeof(UnknownMediaObject), attrs);
// use a new XmlSerializer and a memory stream for deserializting the object as UnknownMediaType.
XmlSerializer xmlSerializer = new XmlSerializer(typeof(UnknownMediaType), o);
using (MemoryStream memoryStream = new MemoryStream())
{
XmlDocument doc = new XmlDocument();
doc.AppendChild(doc.ImportNode(e.Element, true));
doc.Save(memoryStream);
memoryStream.Position = 0;
try
{
// deserialize the object, store the XML element name and insert it into the chapter
UnknownMediaType t = xmlSerializer.Deserialize(memoryStream) as UnknownMediaObject;
t.XmlTagName = e.Element.Name;
show.MediaTypes.Add(t);
}
catch (Exception exc)
{
System.Diagnostics.Debug.WriteLine(exc.ToString());
//return objectType.IsByRef ? null : Activator.CreateInstance(objectType);
}
}
}
BIG BIG问题是序列化对象时此类事件似乎不可用。我得到的输出(不是很令人惊讶)是:
<MultiMediaShow>
<MediaTypes>
<SomeType />
<SomeType />
<AnotherType />
<UnknownMediaType /> // !!!! was 'UnknownTypeFromPluginNotLoaded' !!!!
</MediaTypes>
</MultiMediaShow>
但是,这显然与我反序列化的不一样。所以问题是,我该如何最好地解决这个问题?!?!
非常感谢所有帮助!!
干杯, 菲利克斯
更新
我想知道是否可以以编程方式生成从 UnknownMediaType
派生的类,并且类名取自 UnknownMediaType.XmlTagName
。或者,也可以有一个属性来指定类的 XML 标记名称?
干杯, 菲利克斯
最佳答案
事实上,我动态地实现了一些基于构建类型的工作解决方案。到目前为止,它正在做我想做的事情。目前我看到的唯一缺点是我将它们创建到当前应用程序域中,因此我无法卸载它们(例如,如果加载新节目或插件在运行时可用)。
这是我的代码:
void HandleUnknownElements(Show show, List<XmlElementEventArgs> unknownElementEvents, XmlAttributeOverrides overrides)
{
foreach (XmlElementEventArgs e in unknownElementEvents)
{
// (1) Dynamically create a type that simply inherits from UnknownMediaType
AssemblyName assName = new AssemblyName("Show Dynamic Type " + e.Element.Name + " Assembly");
AssemblyBuilder assBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assName, AssemblyBuilderAccess.Run);
ModuleBuilder modBuilder = assBuilder.DefineDynamicModule(assBuilder.GetName().Name);
TypeBuilder typeBuilder = modBuilder.DefineType(e.Element.Name, TypeAttributes.Class | TypeAttributes.Public, typeof(UnknownMediaType));
Type objectType = typeBuilder.CreateType();
// (2) Add a root attribute to the type as override
XmlAttributes attrs = new XmlAttributes();
XmlRootAttribute xmlRoot = new XmlRootAttribute(e.Element.Name);
attrs.XmlRoot = xmlRoot;
XmlAttributeOverrides o = new XmlAttributeOverrides();
o.Add(objectType, attrs);
// (3) Use a memory stream for creating a temporary XML document that will be deserialized
using (MemoryStream memoryStream = new MemoryStream())
{
XmlDocument doc = new XmlDocument();
doc.AppendChild(doc.ImportNode(e.Element, true));
doc.Save(memoryStream);
memoryStream.Position = 0;
// (4) Deserialize the object using an XmlSerializer and add it
try
{
XmlSerializer xmlSerializer = new XmlSerializer(objectType, o);
UnknownMediaType t = xmlSerializer.Deserialize(memoryStream) as UnknownMediaType;
show.MediaTypes.Add(t);
}
catch (Exception exc)
{
System.Diagnostics.Debug.WriteLine(exc.ToString());
}
}
}
}
如果您发布任何与此有关的问题和您的疑虑,我们将很高兴...
干杯, 菲利克斯
关于c# - 在序列化过程中动态控制 XML 元素名称,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6534717/