【问题标题】:Data contracts: Ignore unknown types on deserialization数据契约:在反序列化时忽略未知类型
【发布时间】:2011-12-12 13:23:28
【问题描述】:

我有一个基于插件的主机应用程序。它的设置被描述为一个数据契约:

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

任何插件都有自己的设置类型。例如:

[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;
}

这可能很糟糕,但它确实有效。 :)

【问题讨论】:

    标签: c# deserialization datacontract


    【解决方案1】:

    我认为理想情况下你应该有一些东西

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

    当您加载应用程序时,您应该使用基于MyPluginCustomAttribute 的反射来初始化obj.PluginSetups,因此只有存在的程序集才会注册其类型。所以你不会有缺少程序集的问题。您也可以使用 Managed Extensibility Framework (MEF) 代替您自己的 MyPluginCustomAttribute

    【讨论】:

    • 问题不是“如何接收可用插件列表及其设置类型”或“如何初始化插件设置”。问题是包含未知类型的对象图的反序列化。
    猜你喜欢
    • 2012-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-16
    相关资源
    最近更新 更多