Den*_*nis 5 c# datacontract deserialization
我有一个基于插件的主机应用程序.其设置被描述为数据合同:
[DataContract(IsReference = true)]
public class HostSetup
{
[DataMember]
public ObservableCollection<Object> PluginSetups
{
get
{
return pluginSetups ?? (pluginSetups = new ObservableCollection<Object>());
}
}
private ObservableCollection<Object> pluginSetups;
}
Run Code Online (Sandbox Code Playgroud)
任何插件都有自己的设置类型.E. g.:
[DataContract(IsReference = true)]
public class Plugin1Setup
{
[DataMember]
public String Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
和
[DataContract(IsReference = true)]
public class Plugin2Setup
{
[DataMember]
public Int32 Percent { get; set; }
[DataMember]
public Decimal Amount { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
在运行时,用户已经配置了主机和插件:
var obj = new HostSetup();
obj.PluginSetups.Add(new Plugin1Setup { Name = "Foo" });
obj.PluginSetups.Add(new Plugin2Setup { Percent = 3, Amount = 120.50M });
Run Code Online (Sandbox Code Playgroud)
然后,我的应用程序已通过DataContractSerializer保存其设置.插件类型作为已知类型传递给序列化程序的构造函数.
这个问题.
用户使用"Plugin2"物理删除程序集,然后启动我的应用程序.
因此,当主机收到可用插件列表时,它对序列化的"Plugin2Setup"实例一无所知.
我想忽略这个实例,让用户在没有"Plugin2"设置的情况下工作.
有没有优雅的方法来做到这一点?
我可以将数据合同序列化为字符串时存储插件的设置:
public ObservableCollection<String> PluginSetups
Run Code Online (Sandbox Code Playgroud)
但它不方便和丑陋.
编辑1
问题是如何反序列化HostSetup实例并忽略序列化的Plugin2Setup实例.
编辑2
我目前的解决方案是:
[DataContract(IsReference = true)]
public class PluginSetupContainer
{
[DataMember]
private String typeName;
[DataMember]
private String rawData;
[OnSerializing]
private void OnSerializing(StreamingContext context)
{
if (SetupParameters != null)
{
using (var writer = new StringWriter())
using (var xmlWriter = new XmlTextWriter(writer))
{
var setupParametersType = SetupParameters.GetType();
var serializer = new DataContractSerializer(setupParametersType);
serializer.WriteObject(xmlWriter, SetupParameters);
xmlWriter.Flush();
typeName = setupParametersType.AssemblyQualifiedName;
rawData = writer.ToString();
}
}
}
[OnSerialized]
private void OnSerialized(StreamingContext context)
{
ClearInternalData();
}
[OnDeserialized]
private void OnDeserialized(StreamingContext context)
{
if (!String.IsNullOrEmpty(typeName) && !String.IsNullOrEmpty(rawData))
{
var setupParametersType = Type.GetType(typeName, false);
if (setupParametersType != null)
{
using (var reader = new StringReader(rawData))
using (var xmlReader = new XmlTextReader(reader))
{
var serializer = new DataContractSerializer(setupParametersType);
SetupParameters = serializer.ReadObject(xmlReader);
}
}
ClearInternalData();
}
}
private void ClearInternalData()
{
typeName = null;
rawData = null;
}
public Object SetupParameters { get; set; }
}
[DataContract(IsReference = true)]
public class HostSetup
{
[DataMember]
public ObservableCollection<PluginSetupContainer> PluginSetups
{
get
{
return pluginSetups ?? (pluginSetups = new ObservableCollection<PluginSetupContainer>());
}
}
private ObservableCollection<PluginSetupContainer> pluginSetups;
}
Run Code Online (Sandbox Code Playgroud)
可能它很糟糕,但它确实有效.:)
我认为理想情况下你应该有一些类似的东西
[DataContract(IsReference = true)]
[MyPluginCustomAttribute]
public class Plugin1Setup
{
}
Run Code Online (Sandbox Code Playgroud)
当您加载应用程序时,您应该obj.PluginSetups使用反射进行初始化,MyPluginCustomAttribute以便只有存在的程序集才注册其类型。所以你不会遇到缺少程序集的问题。您还可以使用托管扩展性框架 (MEF)而不是您自己的MyPluginCustomAttribute