Sometimes, you're just coding away in C# trying to be productive and stuff, and then you realise that this would all be easier in F#. But you can't just switch your whole project over to F# (probably because some Project Manager would get mad or something) - but maybe with a bit of interop magic you can get these two .NET languages to be bros and work together nicely. That way, you get to write glorious F# code, but use a bunch of the C# stuff that's already been done.
F# can use all those objects
Like, yeah, in case you were wondering f# can interact with the rest of the .NET world through objects and stuff. Also, since F# 4.0 object constructors are now grown up functions like everything else which means you can use them in pipe chains (I was really excited when I learned this part).
open System
let makeUri s = "http://" + s |> Uri
F# can make pretty C# classes
This one is obvious given that it can talk to the rest of the .NET world pretty easily, but yes F# can make classes that C# can understand. Interfaces too! This is how you can make some snazzy F# functions and call them from C# code.
type ISomeInterface =
abstract DoAnInterfaceyThing : string -> string
type SomeClassThatImplementsAnInterface () =
interface ISomeInterface with
member x.DoAnInterfaceyThing msg =
"Interface!" + msg
member x.DoAClassThing a = a + 1
These are full fledged classes and interfaces, so you could also implement an interface defined in F# with a class in C# or vice versa. The big difference is when making static classes - there isn't a proper attribute for that (turns out C# has just been lying to you all this time to make things easier) - but you can still make a static class(ish), just make a sealed class with a private constructor and no instance members:
[<Sealed>]
type StaticishClass private () =
static member DoThing a = a + 1
C# can give F# functions
This is possibly the least elegant part of the whole shebang, but if you have some C# code that you would like to pass to an object created in F# as a Func (which is totally a thing you want to do) you will soon come to notice that a C# Func and an F# function are different things. Fortunately, with some fancy F# plumbing that I found over here you can convert your C# trash into glorious F# functions with a tiny little extension method.
open System.Runtime.CompilerServices
[<Extension>]
type public FSharpFuncUtil =
[<Extension>]
static member ToFSharpFunc<'a> (func:System.Func<'a>) = fun () -> func.Invoke()
[<Extension>]
static member ToFSharpFunc<'a,'b> (func:System.Converter<'a,'b>) = fun x -> func.Invoke(x)
[<Extension>]
static member ToFSharpFunc<'a> (func:System.Action<'a>) = fun x -> func.Invoke(x)
[<Extension>]
static member ToFSharpFunc<'a,'b> (func:System.Action<'a,'b>) = fun x -> func.Invoke(x)
[<Extension>]
static member ToFSharpFunc<'a,'b> (func:System.Func<'a,'b>) = fun x -> func.Invoke(x)
[<Extension>]
static member ToFSharpFunc<'a,'b,'c> (func:System.Func<'a,'b,'c>) = fun x y -> func.Invoke(x,y)
[<Extension>]
static member ToFSharpFunc<'a,'b,'c,'d> (func:System.Func<'a,'b,'c,'d>) = fun x y z -> func.Invoke(x,y,z)
static member Create<'a> (func:System.Func<unit, 'a>) = FSharpFuncUtil.ToFSharpFunc func
static member Create<'a,'b> (func:System.Func<'a,'b>) = FSharpFuncUtil.ToFSharpFunc func
static member Create<'a,'b,'c> (func:System.Func<'a,'b,'c>) = FSharpFuncUtil.ToFSharpFunc func
static member Create<'a,'b,'c,'d> (func:System.Func<'a,'b,'c,'d>) = FSharpFuncUtil.ToFSharpFunc func
This then means that you can define a class in F# that would take an F# function:
type SomeClassWithADependency (funcThing : string -> string) =
member x.DoThing(s) = funcThing s
Then you can inject it from your C# code:
public static class FunctionContainer
{
public static string SomeStringFunction(string input) => "So, gosh-darned creative:" + input;
}
public static class Injector
{
public static SomeClassWithADependency GetTheThing() =>
new SomeClassWithADependency(FunctionContainer.SomeStringFunction.ToFSharpFunc());
}
Async is also awesome
If you've added async methods to your code, you might've noticed how it spreads itself around like a virus and now everything returns a Task. F# has a different way of working with async compared to C#, but handily it also provides a neat set of functions for moving between Async<'a> and Task<T>.
let anAsyncFunction thing =
async {
//a task becomes an async
return! Task.FromResult(thing) |> Async.AwaitTask
}
//and back again!
let nowItsATask =
"yo" |> anAsyncFunction |> Async.StartAsTask
And so they both lived happily ever after...