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

Class 如何使用默认构造函数创建记录类,class,f#,constructor,struct,Class,F#,Constructor,Struct,结构得到了默认构造函数,就像我得到的一样 type tagONEDEV_FlowRec = struct ....... end 我可以执行新建设备模型.tagONEDEV\u FlowRec(),但它不适用于此: let (<++|) device bytes size = let unmanagedPtr = Marshal.AllocHGlobal(size : int) Marshal.Copy( (bytes : byte arr

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

type tagONEDEV_FlowRec =
    struct
        .......
    end
我可以执行
新建设备模型.tagONEDEV\u 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)
但是这里没有默认构造函数,结构非常大,可以手动初始化为零,所以如何将这些类与默认构造函数一起使用

如果我找不到解决方案,我想在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; }
在F#中,可以使用隐式语法放置默认构造函数,如

type type(arg1,arg2) =
   let v1 = arg1
   let v2 = arg2
   ....
我认为您使用的
record
方式有点奇怪,在F#中,记录类似于具有命名成员的元组-

编辑

所以问题基本上是你能有一个将记录类型归零的构造函数吗?答案是否定的。在这种情况下,我认为最好的答案是从一个记录切换到一个结构/类,这样你就可以得到你想要的行为


我想到的一个黑客解决方案是使用
System.Reflection.Assembly.CreateInstance
,它有时可以帮助处理类似的事情,但编译器没有提供默认构造函数,因此它无法工作

,因为jpalmer试图解释必须使用参数初始化记录。我想你应该试着用

type MyStruct =
    struct
        val mutable myInt : int
        val mutable myString : string
    end
请看这里:


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

似乎我找到了一个有效的窍门:

[<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
[]
类型tagONEDEV_FlowRec=
班
[]val RecTime:int;
[]val-FlowTime:int;
[]按下键:单个;
[]val T:单个;
[]val DP_V_流量:单个;
[]val音量:双倍;
[]val能量:双倍;
[]val id:UInt16;
new()={}
结束

如果您出于某种原因确实想初始化一条记录,正如John所说,有 “黑客解决方案”

这是我的:(我同意如果你必须这样做,你可能做错了,但我向你保证,我的建议确实对我所做的有帮助:)

让rec记录错误值(x:System.Type)=
如果为x.IsValueType,则为System.Activator.CreateInstance(x)
否则如果(Microsoft.FSharp.Reflection.FSharpType.IsRecord x),则
让cntr=x.GetConstructors()|>Array.pick一些
设值=
cntr.GetParameters()
|>Array.map(乐趣p->p.ParameterType)
cntr.Invoke(值)
否则如果是(Microsoft.FSharp.Reflection.FSharpType.IsTuple(x)),则
设tupleValues=
Microsoft.FSharp.Reflection.FSharpType.GetTupleElements(x)
|>Array.map(默认值)
Microsoft.FSharp.Reflection.FSharpValue.MakeTuple(tupleValue,x)
否则如果(x.IsArray)那么
框(System.Array.CreateInstance(x.GetElementType(),0))
其他的
无效的
让我们为:?>“a”设置一个默认值
以下是您将如何使用它:

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

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

unsafeDefaultValuesFor<B>
A型={
字符串:字符串
Int:Int
StringOption:string选项
}
B类={
字符串:字符串
Int:Int
A:A
}
未列出的错误值
结果是这样的:
{String=null;Int=0;A={String=null;Int=0;StringOption=null;};}

使用CLIMutable声明具有隐式默认构造函数的记录

[<CLIMutable>]
type MyRecord = { MyField: int }
[]
键入MyRecord={MyField:int}
为了防止代码漂移,我推荐下面的样式来支持上面的样式

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

“代码漂移”是指像属性这样的东西在没有任何人注意到的情况下,从它最初打算用于的代码元素漂移出去的趋势。对于第二种样式,由于编辑时的疏忽,属性不太可能偏离声明。

不,这需要做很多工作。我需要没有参数的默认空构造函数。我有一个类,里面有一些结构数组和许多成员/值。我不想为它编写1000行代码构造函数。这不会有他想要的默认构造函数,但通过添加
new()=…
member@Veronica-您必须从记录切换到类/结构查看我的更新答案如果我有一个大的结构或记录类型,则不意味着我需要重新编码。当我使用struct而不是class时,我在PtrToStructure上得到了错误消息:这个结构不应该是类值。参数名:structure。这就是为什么我在寻找类的默认构造函数,而不是使用结构。检查问题更新,我描述了我所说的“真的这么难”对不起,但你问题的第一点是你创建了一个结构,所以我选择了这个。您不能指望我们运行您的部分代码来查找所有警告。我读到你的描述是“defaultconstructor”的问题,而不是结构的问题(在看到你对第一个答案的抱怨之后)。正如您所看到的,您的解决方案基本相同(只是您必须添加DefaultValue Attrib)-我猜您是从我提供的链接中获取解决方案的-对吗很抱歉,如果这没有按预期帮助您。是的,我在提供的链接中找到了解决方案。在您的示例中,您使用的是struct,由于PtrToStructure,我不允许使用它。行new()={}实现了我想要的,DefaultValue允许我不写大的构造函数代码。只做一些类似于
let inline z:'t=fun\uuz->LanguagePrimitives.GenericZero
的事情可能会少一些,然后你就可以编写
val-value:int=z()
,这样可以节省一些时间typing@jpalmer []对我来说似乎更好,我不打字,我复制粘贴…有一刻我已经不需要了,但我真的很喜欢你的解决方案
type A = {
  String : string
  Int : int
  StringOption : string Option
}

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

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