- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我有一个动态创建的类型,所以我无法更改它的实现。我无法应用类似
的解决方案[SoapInclude()]
想象一下,如果我有这样的类(class):
public class BaseClass{}
public class DerivedClass:BaseClass{}
public class AnotherDerivedClass:BaseClass{}
public class RequestClass
{
public BaseClass item{get;set;}
}
如果我们尝试简单地序列化,我们会得到未找到 DerivedClass 的异常,因此我们必须覆盖 xml 属性。我已经设法覆盖我的类型并使用 XmlAttributeOverrides
将其序列化,如下所示:
var requestObject = new RequestClass() {item = new DerivedClass()};
XmlAttributes attrs = new XmlAttributes();
XmlElementAttribute attr = new XmlElementAttribute
{
ElementName = "DerivedClass",
Type = typeof(DerivedClass)
};
attrs.XmlElements.Add(attr);
XmlAttributeOverrides attoverrides = new XmlAttributeOverrides();
attoverrides.Add(typeof(RequestClass), "item", attrs);
XmlSerializer sr = new XmlSerializer(typeof(RequestClass), attoverrides);
StringWriter writer = new StringWriter();
sr.Serialize(writer, requestObject);
var xml = writer.ToString();
现在上面的工作正常,但我想要的是将我的对象序列化为 SOAP 消息。我发现了与上面类似的类 Like SoapAttributeOverrides
并且我尝试用这些类覆盖它但它似乎不起作用。我已经试过了:
var requestObject = new RequestClass(){item = new DerivedClass()};
SoapAttributeOverrides ovr = new SoapAttributeOverrides();
SoapAttributes soapAtts = new SoapAttributes();
SoapElementAttribute element = new SoapElementAttribute();
element.ElementName = "DerivedClass";
ovr.Add(typeof(RequestClass), "item", soapAtts);
var sr = new XmlSerializer(new SoapReflectionImporter(ovr).ImportTypeMapping(typeof(RequestClass)));
StringWriter writer = new StringWriter();
sr.Serialize(writer, requestObject);
var xml = writer.ToString();
writer.Close();
我再次遇到异常 DerivedClass was not found。如何为 SoapElementAttribute
提供类似于 XmlElementAttribute.Type
的类型,以便可以进行序列化以通过覆盖支持 BaseClass
的多态性?
最佳答案
.Net 中的 SOAP 编码 XML 序列化通过 included type 支持多态性机制。为了在运行时将包含的类型添加到 SoapReflectionImporter
,请使用:
SoapReflectionImporter.IncludeType(Type)
SoapReflectionImporter.IncludeTypes(ICustomAttributeProvider)
.因此您可以按如下方式制造您的XmlSerializer
:
public static XmlSerializer RequestClassSerializer { get; }
= CreateSoapSerializerWithBaseClassIncludedTypes(typeof(RequestClass), typeof(DerivedClass), typeof(AnotherDerivedClass));
static XmlSerializer CreateSoapSerializerWithBaseClassIncludedTypes(Type rootType, params Type [] includedTypes)
{
var importer = new SoapReflectionImporter();
foreach (var type in includedTypes)
importer.IncludeType(type);
return new XmlSerializer(importer.ImportTypeMapping(rootType));
}
然后引入如下扩展方法:
public static partial class XmlSerializationHelper
{
public static string GetSoapXml<T>(this T obj, XName wrapperName, XmlSerializer serializer = null)
{
using (var textWriter = new StringWriter())
{
var settings = new XmlWriterSettings() { Indent = true }; // For cosmetic purposes.
using (var xmlWriter = XmlWriter.Create(textWriter, settings))
{
xmlWriter.WriteStartElement(wrapperName.LocalName, wrapperName.NamespaceName);
(serializer ?? GetDefaultSoapSerializer(obj.GetType())).Serialize(xmlWriter, obj);
xmlWriter.WriteEndElement();
}
return textWriter.ToString();
}
}
static readonly Dictionary<Type, XmlSerializer> cache = new Dictionary<Type, XmlSerializer>();
public static XmlSerializer GetDefaultSoapSerializer(Type type)
{
lock(cache)
{
if (cache.TryGetValue(type, out var serializer))
return serializer;
return cache[type] = new XmlSerializer(new SoapReflectionImporter().ImportTypeMapping(type));
}
}
}
您将能够按如下方式序列化您的requestObject
:
var requestObject = new RequestClass(){item = new DerivedClass()};
var xml = requestObject.GetSoapXml("wrapper", RequestClassSerializer);
注意事项:
为避免严重的内存泄漏,您应该静态缓存任何不是使用 XmlSerializer(Type)
或 XmlSerializer(Type, String) 创建的
构造函数。为什么,请参阅 the documentation还有 Memory Leak using StreamReader and XmlSerializer .XmlSerializer
如果您动态生成类型族,您可能需要将它们的序列化器缓存在受 lock
语句保护的静态字典中。
如中所述Extension method to serialize generic objects as a SOAP formatted stream 和 InvalidOperationException while SOAP serialization of complex type 在使用 SOAP XML 序列化程序直接序列化为 XML 之前,您需要手动编写信封或其他包装元素。
如果出于某种原因您只想将 SOAP XML 主体作为一系列 XML 片段,您可以这样做:
public static string GetSoapBodyXml<T>(this T obj, XmlSerializer serializer = null)
{
using (var textWriter = new StringWriter())
{
var settings = new XmlWriterSettings() { Indent = true, ConformanceLevel = ConformanceLevel.Fragment }; // For cosmetic purposes.
using (var xmlWriter = XmlWriter.Create(textWriter, settings))
{
xmlWriter.WriteWhitespace(""); // Hack to prevent an error about WriteStartDocument getting called for ConformanceLevel.Fragment
(serializer ?? GetDefaultSoapSerializer(obj.GetType())).Serialize(xmlWriter, obj);
}
return textWriter.ToString();
}
}
演示 fiddle here .
关于c# - 如何将具有多态性的 c# 对象序列化为具有覆盖的 soapattributes 的 soapmessage,类似于 XmlAttributeOverrides?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57509260/
我来自 Asp.Net 世界,试图理解 Angular State 的含义。 什么是 Angular 状态?它类似于Asp.Net中的ascx组件吗?是子页面吗?它类似于工作流程状态吗? 我听到很多人
我一直在寻找 3 态拨动开关,但运气不佳。 基本上我需要一个具有以下状态的开关: |开 |不适用 |关 | slider 默认从中间开始,一旦用户向左或向右滑动,就无法回到N/A(未回答)状态。 有人
我是一名优秀的程序员,十分优秀!