结构得到了默认构造函数,就像我做的那样
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; - 这就是我想要的默认设置,因为我有更多更大的结构然后编写这样的构造器是邪恶的。
答案 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
是的,我知道有更多的代码行和一个额外的“结构”,“结束”和一些“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 }
“代码漂移”是类似属性的东西偏离最初预期的代码元素的倾向,没有人注意到它。对于第二种风格,由于编辑时粗心大意,属性不太可能偏离声明。