Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create record class with default constructor

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.

like image 310
cnd Avatar asked Oct 11 '11 05:10

cnd


People also ask

Can records have constructors?

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.

Can an object created by using default constructor?

Yes, a constructor can contain default argument with default values for an object.

Who has default constructor to the class?

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() .


2 Answers

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
like image 60
cnd Avatar answered Sep 27 '22 22:09

cnd


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;};}

like image 20
Yodiz Avatar answered Sep 27 '22 22:09

Yodiz