如何使用默认构造函数创建记录类

时间:2011-10-11 05:56:31

标签: class f# constructor struct

结构得到了默认构造函数,就像我做的那样

type tagONEDEV_FlowRec =
    struct
        .......
    end

我可以new DeviceModel.tagONEDEV_FlowRec(),但它无效:

let (<++|) device bytes size =
    let unmanagedPtr = Marshal.AllocHGlobal(size : int)
    Marshal.Copy( (bytes : byte array), 0, unmanagedPtr, size)
    Marshal.PtrToStructure(unmanagedPtr, (device : obj)) // Here
    Marshal.FreeHGlobal(unmanagedPtr)

我需要一个类似的记录课

[<type:StructLayout(LayoutKind.Sequential, Pack=1, CharSet=CharSet.Ansi)>]
type tagONEDEV_FlowRec = { 
    mutable ....;}

type tagONEDEV_FlowRec =
    class
        .......
    end

但是这里没有默认构造函数,并且结构非常大,无法手动初始化它们,所以如何将这些类与默认构造函数一起使用?

如果我找不到解决方案,我认为在C#甚至VB.NET上重新编写这部分将会更快。听起来很像拐杖解决方案,但看起来我还不能用F#OOP部分拨号。

添加:我不想输入的内容是:

               {TimeRec     = 0; 
                Num         = 0us;
                FlagErr     = 0us;
                C6          = 0.0;
                C2H6        = 0.0;
                C3H8        = 0.0;
                CH4         = 0.0;
                CO2         = 0.0;
                iC4H10      = 0.0;
                iC5H12      = 0.0;
                neoC5H12    = 0.0;
                N2          = 0.0;
                nC5H12      = 0.0;
                O2          = 0.0;
                nC4H10      = 0.0;
                He          = 0.0;
                H2          = 0.0;
                H2O         = 0.0;
                id          = 0us; }

&lt; - 这就是我想要的默认设置,因为我有更多更大的结构然后编写这样的构造器是邪恶的。

5 个答案:

答案 0 :(得分:4)

好像我找到了一个工作伎俩:

[<type:StructLayout(LayoutKind.Sequential, Pack=1, CharSet=CharSet.Ansi)>]
type tagONEDEV_FlowRec =
    class
        [<DefaultValue>] val RecTime         : int;
        [<DefaultValue>] val FlowTime        : int;
        [<DefaultValue>] val AbsPress        : single;
        [<DefaultValue>] val T               : single;
        [<DefaultValue>] val DP_V_FlowRate   : single;
        [<DefaultValue>] val Volume          : double;
        [<DefaultValue>] val Energy          : double;
        [<DefaultValue>] val id              : UInt16;
        new() = {} 
    end

答案 1 :(得分:3)

在F#中,您可以使用隐式语法(如

)放置默认构造函数
type type(arg1,arg2) =
   let v1 = arg1
   let v2 = arg2
   ....

我认为您使用record的方式有点奇怪,在F#中,记录类似于具有命名成员的元组 - http://msdn.microsoft.com/en-us/library/dd233184.aspx

修改

所以问题基本上是你有一个构造函数可以将记录类型归零 - 回答否。在这种情况下,我认为最好的答案是从记录切换到结构/类,以便您可以获得所需的行为。

我想到的一个hackish解决方案是使用System.Reflection.Assembly.CreateInstance,它有时可以帮助这样的事情,但编译器不提供默认构造函数,因此它不起作用

答案 2 :(得分:3)

因为jpalmer试图解释一条记录必须用参数初始化。我认为你应该尝试使用

type MyStruct =
    struct
        val mutable myInt : int
        val mutable myString : string
    end

见这里:MSDN Docs Explicit Fields

是的,我知道有更多的代码行和一个额外的“结构”,“结束”和一些“val”但这真的很难吗?如果您在类型上使用1000个属性,则无论如何都应重新考虑代码。

答案 3 :(得分:3)

如果你出于某种原因确实想要初始化一条记录,正如约翰所说的那样 “hackish solution”。

这是我的:(我同意如果你必须这样做,你可能做错了,但我向你保证我真的帮助我做的事情:)。

let rec unsafeDefaultValues (x:System.Type) = 
  if x.IsValueType then System.Activator.CreateInstance(x)
  else if (Microsoft.FSharp.Reflection.FSharpType.IsRecord x) then
    let cntr = x.GetConstructors() |> Array.pick Some
    let values = 
      cntr.GetParameters()
      |> Array.map (fun p -> unsafeDefaultValues p.ParameterType)
    cntr.Invoke(values)
  else if (Microsoft.FSharp.Reflection.FSharpType.IsTuple(x)) then
    let tupleValues = 
      Microsoft.FSharp.Reflection.FSharpType.GetTupleElements(x)
      |> Array.map (unsafeDefaultValues)
    Microsoft.FSharp.Reflection.FSharpValue.MakeTuple(tupleValues, x)
  else if (x.IsArray) then
    box (System.Array.CreateInstance(x.GetElementType(), 0))
  else
    null

let unsafeDefaultValuesFor<'a> = unsafeDefaultValues typeof<'a> :?> 'a

这里结束你将如何使用它:

type A = {
  String : string
  Int : int
  StringOption : string Option
}

type B = {
  String : string
  Int : int
  A : A  
}

unsafeDefaultValuesFor<B>

结果如下: {String = null; Int = 0; A = {String = null; Int = 0; StringOption = null;};}

答案 4 :(得分:0)

使用CLIMutable声明一个带有隐式默认构造函数的记录。

[<CLIMutable>]
type MyRecord = { MyField: int }

为了防止代码漂移,我建议使用以下样式来支持上述内容。

type [<CLIMutable>] MyRecord = { MyField: int }

“代码漂移”是类似属性的东西偏离最初预期的代码元素的倾向,没有人注意到它。对于第二种风格,由于编辑时粗心大意,属性不太可能偏离声明。