【发布时间】:2021-12-18 04:51:09
【问题描述】:
我正在使用 Xml 存储应用程序的设置,这些设置在运行时更改,并在应用程序执行期间多次序列化和反序列化。
有一个 Xml 元素可以保存任何可序列化的类型,并且应该从 Object 类型的属性进行序列化和反序列化,即
[Serializable]
public class SetpointPoint
{
[XmlAttribute]
public string InstrumentName { get; set; }
[XmlAttribute]
public string Property { get; set; }
[XmlElement]
public object Value { get; set; }
} // (not comprehensive, only important properties displayed)
Xml,
<?xml version="1.0" encoding="utf-8"?>
<StationSetpoints xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:schemaLocation="http://www.w3schools.com StationSetpoints.xsd">
<Setpoint PartNumber="107983">
<Point InstrumentName="PD Stage" Property="SetPoint">
<Value xsi:type="xsd:string">3</Value>
</Point>
<Point InstrumentName="TR Camera" Property="MeasurementRectangle" StationSetpointMemberType="Property">
<Value xsi:type="xsd:string">{X=145,Y=114,Width=160,Height=75}</Value>
</Point>
</Setpoint>
</StationSetpoints>
我反序列化 Xml 并解析属性以通过“InstrumentName”查找仪器对象,并且该仪器将具有与 Xml 属性“Property”同名的属性,我的意图是设置该 instrument.property = xml 中的 Value 元素。使用反射转换对象很简单,例如(在 vb.net 中)
Dim ii = InstrumentLoader.Factory.GetNamed(point.InstrumentName)
Dim pi = ii.GetType().GetProperty(point.Property)
Dim tt = pi.PropertyType
Dim vt = Convert.ChangeType(point.Value, tt)
pi.SetValue(ii, vt)
是的,如果 point.Value 是一个对象,它就可以工作,但它不是。从对象中序列化的结果是一个字符串。在属性是 Double 的情况下,我们得到
<Value xsi:type="xsd:string">3</Value>
产生"3",当一个System.Drawing.Rectangle,
<Value xsi:type="xsd:string">{X=145,Y=114,Width=160,Height=75}</Value>
收益"{X=145,Y=114,Width=160,Height=75}"
那么有没有办法将值类型或对象的 Xml 表示形式直接转换为 .NET 等效项?
(或者我必须使用 Reflection / System.Activator 手动实例化对象并转换(在基元的情况下)或字符串解析属性和值(在非基元的情况下)?)
【问题讨论】:
-
您可以使用
XmlElement属性多次注释Value属性,指定正确的类型,如下所示:[XmlElement(type=typeof(string)),XmlElement(type=typeof(System.Drawing.Rectangle))],然后使用模式匹配来读取值。 -
XmlSerializer仅支持静态预先声明的派生类型的序列化。为此,请参阅Using XmlSerializer to serialize derived classes。 -
@Eldar 我想保留这个开放式以支持其他类型。配置仅在xml中,无需重新编译。我的意思是任何可以用 XML 表示的东西,比如 Rectangle,当然还有原语。
-
@dbc 我很欣赏这个链接,但看不到它如何适用于我的问题。
-
那么有没有办法将值类型或对象的 Xml 表示形式直接转换为 .NET 等效项? -- 关键是
XmlSerializer没有t 支持将多态字段序列化和反序列化为开箱即用的仅在运行时定义的类型。如果您可以静态定义可能的类型,您的生活会更轻松。但如果没有,您将需要做一些棘手的事情,例如在SetpointPoint上实现IXmlSerializable并手动执行。 (还有一些像Color这样的类型不能直接被XmlSerializer序列化。)
标签: c# xml vb.net xml-serialization