2015-07-28 3 views
2

Я использую DataContract для сериализации/десериализации объектов на машине пользователя. Таким образом, в основном сценарий сохранения/загрузки.Внедрение сопоставления между различными типами (bool? И enum) с использованием DataContract

У меня есть DataContract, которая была упорядоченная DataMember типа bool? и теперь мне нужно изменить его на Enum. Он заказан, потому что один из сериализаторов - protobuf-net.

Как это выглядит сейчас:

[DataContract] 
public class Result 
{ 
    [DataMember(Order = 3)] 
    public bool? Accepted { get; set; } 
} 

Это должно быть:

public enum ResultDecisionStatus 
{ 
    Accepted, //// map as 'true' for 'bool?' 
    Rejected, //// map as 'false' for 'bool?' 
    Neutral, //// new 
    Unknown //// map as 'null' for 'bool?' 
} 

[DataContract] 
public class Result 
{ 
    [DataMember(Order = 4?)] //// I assume ordering might have to change 
    public ResultDecisionStatus DecisionStatus { get; set; } 
} 

я реализовал следующие, мне кажется, чтобы быть Hacky, но, кажется, работает. Я оставил Accepted в том же заказе и изменил его на private и установил переменную, чтобы сопоставить ее с новым Enum при десериализации. Это хороший дизайн? Это странно.

[DataContract] 
public class Result 
{ 
    [DataMember(Order = 4)] 
    public ResultDecisionStatus DecisionStatus { get; set; } 

    [DataMember(Order = 3)] 
    private bool? Accepted { get; set; } 

    [DataMember(Order = 1003)] 
    private bool AcceptedToDecisionStatusMapped { get; set; } 

    [OnDeserialized] 
    private void OnDeserialized(StreamingContext context) 
    { 
     if (!AcceptedToDecisionStatusMapped) 
     { 
      switch(Accepted) 
      { 
       case true: 
        DecisionStatus = ResultDecisionStatus.Accepted; 
        break; 
       case false: 
        DecisionStatus = ResultDecisionStatus.Rejected; 
        break; 
       case null: 
        DecisionStatus = ResultDecisionStatus.Unknown; 
        break; 
      } 
      AcceptedToDecisionStatusMapped = true; 
     } 
    } 
} 

Вопрос: Есть ли надлежащим образом реализовать отображение между типами для упорядоченного DataContracts без сохранения старых членов и добавление дополнительных свойств отображения для каждой версии?

ответ

1

Попробуйте это:

[DataContract] 
public class Result 
{ 
    private ResultDecisionStatus? _decisionStatus; 

    [DataMember(Order = 3)] 
    public bool? Accepted { get; set; } 

    [DataMember(Order = 4)] 
    public ResultDecisionStatus DecisionStatus 
    { 
     get 
     { 
      if (_decisionStatus.HasValue) 
      { 
       return _decisionStatus.Value; 
      } 
      else if (Accepted.HasValue) 
      { 
       return Accepted.Value 
        ? ResultDecisionStatus.Accepted 
        : ResultDecisionStatus.Rejected; 
      } 
      else 
      { 
       return ResultDecisionStatus.Unknown; 
      } 
     } 
     set 
     { 
      _decisionStatus = value; 
     } 
    } 
} 

Это должно в основном позволяют передавать данные, используя старый контракт и новый для взаимодействия. Было бы странно, если бы использовались и 3, и 4, но я предполагаю, что это будет либо один, либо другой в вашем случае.

Update:

Смотрите мой другой ответ. В вашем случае, поскольку логическое значение может легко сопоставляться с значениями перечисления, существует более простой способ. Оставив этот ответ для случая, когда у кого-то может не быть этой роскоши.

+0

О, аккуратно, что избавляется от отображаемой переменной. Вероятно, нет способа избавиться от «Принято»? – Vlad

+0

Да, не без взлома B/C. – Jacob

+0

См. Мой другой ответ; это должно быть лучшим способом, если он работает, и он не вводит никаких новых полей. – Jacob

1

Похоже bool и int32 совместимы в Protobuf, так что вы можете сделать это:

public enum ResultDecisionStatus 
{ 
    Rejected = 0, // will catch old boolean false values 
    Accepted = 1, // will catch old boolean true values 
    Neutral = 2 // new 
} 

[DataContract] 
public class Result 
{ 
    [DataMember(Order = 3)] 
    public ResultDecisionStatus? DecisionStatus { get; set; } 
} 

Просто используйте null стоять Unknown.

+0

Это выглядит очень просто, но, похоже, это не работает для меня. Я все время возвращаю как «нуль». У меня есть viewmodels, которые завершают «Результаты» и имеют преобразователи из «DecisionStatus» в источник изображения, и когда я отлаживаю конвертер, все значения начинаются как «null». Теперь десериализация выполняется с помощью 'XmlSerializer'. Не хотел вникать в специфику, но у меня есть несколько возможных десериализаторов на основе предыдущих версий программного обеспечения. Ваш другой ответ работал отлично. Я буду продолжать, но если я не смогу добиться успеха, я просто приму свой другой ответ. – Vlad

+0

Да, отладка его от десериализации, все значения возвращаются как «null». Может быть, это связано с сериализатором? – Vlad

+0

Я вижу, это, вероятно, не сработает, если в некоторых случаях вы используете 'XmlSerializer', а в других - protobuf-net', поскольку в случае XML не будет автоматического принуждения между bool и перечислениями. Так что другой ответ, вероятно, лучше для вашего дела, и было бы лучше, если бы это был просто протобуф. – Jacob

 Смежные вопросы

  • Нет связанных вопросов^_^