We came across an issue recently with F# code calling into C# code. I have simplified the issue down as simple as I can. The C# code is as follows:
using System;
namespace CSharpLib
{
public abstract class InputMessageParent
{
public readonly Guid Id;
protected InputMessageParent(Guid id) { this.Id = id; }
}
public class Result { public string ResultString; }
public enum FunctionResult
{
None,
Good,
Bad
}
public class ConfigurationBuilder
{
public Result DoWork<TMessage>(
string param1,
Func<TMessage, FunctionResult> action)
where TMessage : InputMessageParent
{
return new Result() { ResultString = "Good" };
}
}
}
The F# code needs to call the ConfigurationBuilders DoWork function. Note that the DoWork function takes two parameters, a simple string and a Func as a second parameter. The Func takes in a TMessage which must inherit from InputMessageParent and it returns a simple Result type. The F# code is as follows:
open System
type InputMessageConcreteTypeA =
inherit CSharpLib.InputMessageParent
val Property1:string
new (id, property1Value) =
{
inherit CSharpLib.InputMessageParent(id)
Property1 = property1Value
}
[<EntryPoint>]
let main argv =
let actionImpl (input:InputMessageConcreteTypeA) =
CSharpLib.FunctionResult.Good
let builder = new CSharpLib.ConfigurationBuilder()
builder.DoWork("param1", actionImpl) |> ignore
0
This code does not compile. The actionImpl type is InputMessageConcreteTypeA -> CSharpLib.FunctionResult, this is exactly the type of the second parameter that DoWork is expecting but instead it gives me the following error: This expression was expected to have type 'Func<'a,CSharpLib.FunctionResult>' but here has type 'b -> CSharpLib.FunctionResult'
Interestingly, if I change the code to the following its does compile:
[<EntryPoint>]
let main argv =
let actionImpl (input:InputMessageConcreteTypeA) =
CSharpLib.FunctionResult.Good
let builder = new CSharpLib.ConfigurationBuilder()
builder.DoWork("param1", fun input -> actionImpl(input)) |> ignore
0
Why does the code compile for the inline anonymous function which is the exact same type definition as actionImpl but wont compile if I just pass actionImpl directly? The inline anonymous function looks pretty pointless but is the only solution that we have at the moment. Is there a better way?