2011-12-19 5 views
6

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

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

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

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 части пространства имен), который представляет значения не имеющие какие-либо данных, и нет никаких свойств в базовом классе, где вы можете установить значения, не содержащие каких-либо данных.

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

ответ

1

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

РЕДАКТИРОВАТЬ: Составленный форма ПН, в то время как деталь реализации, являетсяdefined in the spec и поэтому вряд ли изменится. Однако, излагая типы, вы делаете это явным и мешает вам работать с нулевыми случаями.

3

Если вы зададите тип 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 
+0

Я пропустил это в своем сообщении выше. Конечно, у DU был атрибут knowntype. – Kristian