structures got default constructors like if I do
type tagONEDEV_FlowRec =
struct
.......
end
I can do new DeviceModel.tagONEDEV_FlowRec()
but it doesn't work with this :
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)
I need a record class here alike
[<type:StructLayout(LayoutKind.Sequential, Pack=1, CharSet=CharSet.Ansi)>]
type tagONEDEV_FlowRec = {
mutable ....;}
or
type tagONEDEV_FlowRec =
class
.......
end
but there is no default constructor here and structures is very big to zero init them manually, so how can I use such classes with default constructors ?
If I will not find the solution I think that will be faster for me to recode this part on C# or even on VB.NET. Sounds alike crutch-solution but looking like I can't dial with F# OOP part yet.
an addition: the thing I don't want to type is :
{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; }
<- that is what I want to have by default, because I've got much lager structures then this and writing such constuctors is wicked.
However, a record must always contain the canonical constructor. The record contains fields that are declared in the parentheses that follow the type name, and the canonical constructor initializes those fields from its arguments. If you do not provide this canonical constructor, the compiler creates it automatically.
Yes, a constructor can contain default argument with default values for an object.
A default constructor is a constructor that either has no parameters, or if it has parameters, all the parameters have default values. If no user-defined constructor exists for a class A and one is needed, the compiler implicitly declares a default parameterless constructor A::A() .
Seems like I found a working trick :
[<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
If you for some reason really do want to initialize a record, as John said, there are "hackish solution"s.
Here is mine: (I agree with if you have to do this, you probably are doing it wrong, but i assure you mine really helped for what i was doing :).
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
End here is how you would use it:
type A = {
String : string
Int : int
StringOption : string Option
}
type B = {
String : string
Int : int
A : A
}
unsafeDefaultValuesFor<B>
And the result would look like this: {String = null; Int = 0; A = {String = null; Int = 0; StringOption = null;};}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With