F #, сериализует разграниченные союзы со значениями, не имеющими данных - PullRequest
6 голосов
/ 19 декабря 2011

Прежде всего, я должен сказать, что я знаю, что, как правило, не очень хорошая идея использовать специфичные для F # вещи при интеграции с другими языками в .NET.

Моя проблема в том, что я не понимаю, каксоздать сервисную ссылку на сервис, содержащий методы, раскрывающие дискриминационные объединения.

Я получаю основы, которые выглядят примерно так:

  type TelephonyProductActivationData =
  | MobileUseNextIcc 
  | Mobile of decimal
  | MobileBroadbandUseNextIcc
  | MobileBroadband of decimal
  | Fixed
  | Voip of int16 * int16
  static member KnownTypes() =
      typeof<TelephonyProductActivationData>.GetNestedTypes(BindingFlags.Public ||| BindingFlags.NonPublic) |> Array.filter FSharpType.IsUnion

Если вы используете интерактивную F # для первого создания типа:

type TelephonyProductActivationData =
  | MobileUseNextIcc of unit
  | Mobile of decimal<Icc>
  | MobileBroadbandUseNextIcc of unit
  | MobileBroadband of decimal<Icc>
  | Fixed of unit
  | Voip of BoxNr * int16<BoxPort>;;

И вывыполнить часть кода knowntypes (слегка измененную):

(typeof<TelephonyProductActivationData>.GetNestedTypes(System.Reflection.BindingFlags.Public ||| System.Reflection.BindingFlags.NonPublic) |> Array.filter Microsoft.FSharp.Reflection.FSharpType.IsUnion) |> Array.map (fun x -> x.FullName);;

вы увидите следующий вывод:

val it : string [] =
  [|"FSI_0047+TelephonyProductActivationData+Mobile";
    "FSI_0047+TelephonyProductActivationData+MobileBroadband";
    "FSI_0047+TelephonyProductActivationData+Voip"|]

Обратите внимание, что значения, не имеющие данных, связанных с ними, пропали.Это означает, что никакие типы не будут созданы при компиляции этого различенного объединения.Выполнив это утверждение в F # интерактиве:

typeof<TelephonyProductActivationData>.GetProperties() |> Array.map (fun x -> (x.Name));;

, мы увидим, кем они стали:

val it : string [] =
  [|"Tag"; "IsVoip"; "Fixed"; "IsFixed"; "IsMobileBroadband";
    "MobileBroadbandUseNextIcc"; "IsMobileBroadbandUseNextIcc"; "IsMobile";
    "MobileUseNextIcc"; "IsMobileUseNextIcc"|]

Как вы можете видеть, значения без связанных с ними данных стали свойствами.Теперь я могу показать вам настоящую проблему.При создании ссылки на службу с помощью этого метода все, что я получаю, это:

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="ActivationModel.TelephonyProductActivationData", Namespace="http://schemas.datacontract.org/2004/07/Svea.Inri.Data")]
[System.SerializableAttribute()]
[System.Runtime.Serialization.KnownTypeAttribute(typeof(ConsoleApplication1.ServiceReference1.ActivationModelTelephonyProductActivationData.Mobile))]
[System.Runtime.Serialization.KnownTypeAttribute(typeof(ConsoleApplication1.ServiceReference1.ActivationModelTelephonyProductActivationData.MobileBroadband))]
[System.Runtime.Serialization.KnownTypeAttribute(typeof(ConsoleApplication1.ServiceReference1.ActivationModelTelephonyProductActivationData.Voip))]
public partial class ActivationModelTelephonyProductActivationData : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged {

    [System.NonSerializedAttribute()]
    private System.Runtime.Serialization.ExtensionDataObject extensionDataField;

    private int _tagField;

    [global::System.ComponentModel.BrowsableAttribute(false)]
    public System.Runtime.Serialization.ExtensionDataObject ExtensionData {
        get {
            return this.extensionDataField;
        }
        set {
            this.extensionDataField = value;
        }
    }

    [System.Runtime.Serialization.DataMemberAttribute(IsRequired=true)]
    public int _tag {
        get {
            return this._tagField;
        }
        set {
            if ((this._tagField.Equals(value) != true)) {
                this._tagField = value;
                this.RaisePropertyChanged("_tag");
            }
        }
    }

    public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged(string propertyName) {
        System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
        if ((propertyChanged != null)) {
            propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
        }
    }

    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
    [System.Runtime.Serialization.DataContractAttribute(Name="ActivationModel.TelephonyProductActivationData.Mobile", Namespace="http://schemas.datacontract.org/2004/07/Svea.Inri.Data")]
    [System.SerializableAttribute()]
    public partial class Mobile : ConsoleApplication1.ServiceReference1.ActivationModelTelephonyProductActivationData {

        private decimal itemField;

        [System.Runtime.Serialization.DataMemberAttribute(IsRequired=true)]
        public decimal item {
            get {
                return this.itemField;
            }
            set {
                if ((this.itemField.Equals(value) != true)) {
                    this.itemField = value;
                    this.RaisePropertyChanged("item");
                }
            }
        }
    }

    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
    [System.Runtime.Serialization.DataContractAttribute(Name="ActivationModel.TelephonyProductActivationData.MobileBroadband", Namespace="http://schemas.datacontract.org/2004/07/Svea.Inri.Data")]
    [System.SerializableAttribute()]
    public partial class MobileBroadband : ConsoleApplication1.ServiceReference1.ActivationModelTelephonyProductActivationData {

        private decimal itemField;

        [System.Runtime.Serialization.DataMemberAttribute(IsRequired=true)]
        public decimal item {
            get {
                return this.itemField;
            }
            set {
                if ((this.itemField.Equals(value) != true)) {
                    this.itemField = value;
                    this.RaisePropertyChanged("item");
                }
            }
        }
    }

    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
    [System.Runtime.Serialization.DataContractAttribute(Name="ActivationModel.TelephonyProductActivationData.Voip", Namespace="http://schemas.datacontract.org/2004/07/Svea.Inri.Data")]
    [System.SerializableAttribute()]
    public partial class Voip : ConsoleApplication1.ServiceReference1.ActivationModelTelephonyProductActivationData {

        private string item1Field;

        private short item2Field;

        [System.Runtime.Serialization.DataMemberAttribute(IsRequired=true)]
        public string item1 {
            get {
                return this.item1Field;
            }
            set {
                if ((object.ReferenceEquals(this.item1Field, value) != true)) {
                    this.item1Field = value;
                    this.RaisePropertyChanged("item1");
                }
            }
        }

        [System.Runtime.Serialization.DataMemberAttribute(IsRequired=true)]
        public short item2 {
            get {
                return this.item2Field;
            }
            set {
                if ((this.item2Field.Equals(value) != true)) {
                    this.item2Field = value;
                    this.RaisePropertyChanged("item2");
                }
            }
        }
    }
}

Нет никаких подклассов для ActivationModelTelephonyProductActivationData (часть ActivationModel является пространством имен), который представляет значения, не имеющие каких-либо данных, и естьнет свойств в базовом классе, где вы можете установить значения, не имеющие никаких данных.

Мой вопрос, наконец, как это сделать.Нужно ли мне добавлять «единицы» ко всем моим разграниченным значениям объединений, у которых нет данных.

Ответы [ 2 ]

3 голосов
/ 06 января 2012

Если вы определите тип DU, как показано ниже, он будет работать.

[<KnownType("KnownTypes")>]
//[<DataContract>] // note: keep KnownTypes, but avoid DataContract 
//  so that DataContractSerializer uses .NET 'Serializable' instead
type TelephonyProductActivationData = 
  | MobileUseNextIcc
  | Mobile of decimal 
  | MobileBroadbandUseNextIcc
  | MobileBroadband of decimal 
  | Fixed
  | Voip of int16 * int16 
  static member KnownTypes() = 
      typeof<TelephonyProductActivationData>.GetNestedTypes(BindingFlags.Public |||
                                                            BindingFlags.NonPublic) 
      |> Array.filter FSharpType.IsUnion 
1 голос
/ 19 декабря 2011

Вы, в сущности, зависите от деталей реализации (скомпилированной формы DU), чтобы это работало.Даже изменение каждого случая, чтобы быть ненулевым, пахнет мной.Я думаю, что идеальным решением является использование классов.DU примерно соответствует абстрактному базовому классу для типа DU и подклассу для каждого случая.Вы можете создать иерархию типов самостоятельно, добиться аналогичного эффекта и получить лучшие результаты.

РЕДАКТИРОВАТЬ : скомпилированная форма DU, в то время как детали реализации, - определено в спецификации и поэтому вряд ли изменится.Тем не менее, размещение типов самостоятельно делает это явным и мешает вам обходить нулевые случаи.

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