Контракты данных: игнорировать неизвестные типы при десериализации - PullRequest
5 голосов
/ 12 декабря 2011

У меня есть хост-приложение на основе плагинов.Его настройки описываются как контракт данных:

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

Может быть, это ужасно, но это работает.:)

1 Ответ

0 голосов
/ 12 декабря 2011

Я думаю, что в идеале у вас должно быть что-то в строках

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

, и когда вы загружаете приложение, вы должны инициализировать obj.PluginSetups, используя отражение на основе MyPluginCustomAttribute, так что только присутствующие сборки имеют свои типызарегистрировано.Таким образом, у вас не будет проблемы с отсутствующими сборками.Вы также можете использовать Managed Extensibility Framework (MEF) вместо своего MyPluginCustomAttribute

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...