2011-12-12 35 views
5

我有一个基于插件的主机应用程序。其设置被描述为数据合同:数据合同:忽略未知类型的反序列化

[DataContract(IsReference = true)] 
public class HostSetup 
{ 
    [DataMember] 
    public ObservableCollection<Object> PluginSetups 
    { 
     get 
     { 
      return pluginSetups ?? (pluginSetups = new ObservableCollection<Object>()); 
     } 
    } 
    private ObservableCollection<Object> pluginSetups;   
} 

任何插件都有其自己的设置类型。 E.摹:

[DataContract(IsReference = true)] 
public class Plugin1Setup 
{ 
    [DataMember] 
    public String Name { get; set; } 
} 

[DataContract(IsReference = true)] 
public class Plugin2Setup 
{ 
    [DataMember] 
    public Int32 Percent { get; set; } 
    [DataMember] 
    public Decimal Amount { get; set; } 
} 

在运行时,用户已配置的主机和插件这样的方式:

 var obj = new HostSetup(); 
     obj.PluginSetups.Add(new Plugin1Setup { Name = "Foo" }); 
     obj.PluginSetups.Add(new Plugin2Setup { Percent = 3, Amount = 120.50M }); 

然后,我的应用程序已经保存了通过DataContractSerializer设置。插件类型作为已知类型传递给序列化器的构造函数。

这个问题。
用户通过“Plugin2”物理删除程序集,然后启动我的应用程序。
因此,当主机收到可用插件的列表时,它对序列化的“Plugin2Setup”实例一无所知。

我想忽略这个实例,并让用户在没有“Plugin2”设置的情况下工作。
有没有优雅的方式来做到这一点?
我可以存储插件设置为数据契约序列化到字符串:

public ObservableCollection<String> PluginSetups 

,但它不是方便和丑陋。

编辑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; 
} 

可能是可怕的,但它的工作原理。 :)

回答

0

我觉得最好你应该有对

[DataContract(IsReference = true)] 
[MyPluginCustomAttribute] 
public class Plugin1Setup 
{ 
} 

线的东西,当你的应用程序加载,你应该使用基于MyPluginCustomAttribute所以只有那些存在组件反射初始化obj.PluginSetups有注册它们的类型。所以你不会有缺少组件的问题。您还可以使用Managed Extensibility Framework (MEF),而不是你自己的MyPluginCustomAttribute

+0

问题不在于“如何得到可用的插件及其设置类型的列表”或“如何初始化插件设置”。问题是包含未知类型的对象图的反序列化。 – Dennis

相关问题