2011-12-12 37 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

相關問題