After earlier failure, I decided to revisit the use of CSLA with F#. I keep running into the same issue in that the static RegisterProperty throws a typeinitializationexception. I wrote a test combo C# / F# solution with 2 libraries and a console app displayed below. I wrote a csla C# object, a duplicate (I think) F# object and a console app that instantiates both of them. The most interesting aspect of this is if I remove the static modifiers from the propertyinfo and registerproperty calls in the F# object, it works, but only for 1 object. A subsequent call gives the expected error that the property has already been registered.
I ran both DLLs through a decompiler and C# creates the expected call to RegisterProperty in the static constructor. However the F# does not create the same static constructor call.
Does anyone know why this is happening in the F# class? Also, has anyone had any luck building CSLA apps within F#. If so, then I'm likely guilty of operator error and could use some guidance.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RunCSharpVsFSharp
{
class Program
{
static void Main(string[] args)
{
// Call to CSharpObjects below works correctly
try
{
var a = CSharpObjects.EditableRoot.GetEditableRoot();
a.Name = "David Gilmour";
}
catch(System.Exception ex)
{
throw ex;
}
// below code results in a typeinitializationexception with inner exception message
// of "Attempt by method '<StartupCode$FSharpObjects>.$EditableRoot..cctor()' to access method
// 'Csla.BusinessBase`1<FSharpObjects.EditableRoot>.RegisterProperty<System.String>(Csla.PropertyInfo`1<System.String>)'
// failed."
try
{
var a = FSharpObjects.EditableRoot.GetEditableRoot;
a.Name = "Roger Waters";
}
catch (System.Exception ex)
{
throw ex;
}
}
}
}
======================================================================
namespace FSharpObjects
open System.Collections.Generic
open System.Linq
open System.Text
open System.Threading.Tasks
open Csla
open Csla.Serialization
type public EditableRoot() =
inherit BusinessBase<EditableRoot>()
static let propinfo = new PropertyInfo<string>("Name")
static let NameProperty = EditableRoot.RegisterProperty<string>(typeof<EditableRoot>,propinfo)
member x.Name
with get() = x.GetProperty(NameProperty)
and set(value) = x.SetProperty(NameProperty, value);
static member GetEditableRoot = new EditableRoot()
======================================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Csla;
namespace CSharpObjects
{
[Serializable]
public class EditableRoot : BusinessBase<EditableRoot>
{
private EditableRoot()
{
}
private static PropertyInfo<string> propinfo = new PropertyInfo<string>("Name");
public static readonly PropertyInfo<string> NameProperty = RegisterProperty<string>(propinfo);
public string Name
{
get { return GetProperty(NameProperty); }
set { SetProperty(NameProperty, value); }
}
public static EditableRoot GetEditableRoot()
{
return new EditableRoot();
}
}
}
I haven't done anything with F#, so I can't really help.
CSLA does rely heavily on the standard static type initialization behaviors provided by the C# and VB compilers. If F# provides some alternate static type initialization behavior then you'll need to figure out some way to trigger the required behaviors in your own code.
Copyright (c) Marimer LLC