F#,序列化具有缺乏数据值的歧视联盟
问题描述:
首先,我不得不说,我知道在.NET中与其他语言集成时使用F#特定的东西通常不是一个好主意。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部分是命名空间),表示没有任何数据值和有没有属性在基类中您可以设置没有任何数据的值。
我的问题是最后,人们应该如何做到这一点。我是否必须将“单位”添加到没有数据的所有区分的联合数值中。
答
您实质上依赖于实现细节(DU的编译形式)以使其工作。即使将每种情况都改变为非空洞的气味,对我来说也是如此。我认为理想的解决方案是使用类。 DU大致对应于DU类型的抽象基类和每种情况的子类。您可以自己创建类型层次结构,获得类似的效果,并获得更好的结果。
EDIT:下游用户的已编译的形式,而实现的细节,是defined in the spec,因此不太可能改变。但是,自己布置类型使其明确,并防止您必须在无用案件中工作。
答
如果像下面那样定义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
我错过了在我上面的帖子。当然,DU有知识类型属性。 – Kristian 2012-01-17 13:58:30