模式匹配C#代码中的F#类型

ДМИ*_*КОВ 4 c# f# interop

假设有一个F#定义:

type Either<'a,'b> = | Left of 'a | Right of 'b

let f (i : int) : Either<int, string> =
    if i > 0
        then Left i
        else Right "nothing"
Run Code Online (Sandbox Code Playgroud)

函数f用于C#代码:

var a = Library.f(5);
Run Code Online (Sandbox Code Playgroud)

结果值如何a与数据构造函数进行模式匹配?就像是:

/*
(if a is Left x)
    do something with x
(if a is Right y)
    do something with y
*/
Run Code Online (Sandbox Code Playgroud)

Tom*_*cek 7

使用来自C#的F#区分联合有点不优雅,因为它们是如何编译的.

我认为最好的方法是定义一些成员(在F#方面),这将简化使用C#中的类型.有多个选项,但我更喜欢的是定义TryLeft和TryRight行为类似的方法Int32.TryParse(因此他们应该熟悉使用您的F#API的C#开发人员):

open System.Runtime.InteropServices

type Either<'a,'b> = 
  | Left of 'a 
  | Right of 'b
  member x.TryLeft([<Out>] a:byref<'a>) =
    match x with Left v -> a <- v; true | _ -> false
  member x.TryRight([<Out>] b:byref<'b>) =
    match x with Right v -> b <- v; true | _ -> false
Run Code Online (Sandbox Code Playgroud)

然后您可以使用C#中的类型,如下所示:

int a;
string s;
if (v.TryLeft(out a)) Console.WriteLine("Number: {0}", a);
else if (v.TryRight(out s)) Console.WriteLine("String: {0}", s);
Run Code Online (Sandbox Code Playgroud)

你这样做会失去一些F#安全性,但是在没有模式匹配的语言中这是预期的.但好的是,任何熟悉.NET的人都应该能够使用F#中实现的API.

另一种方法是定义使用左/右案例携带的值Match来接受Func<'a>和Func<'b>委托并调用右代理的成员.从功能角度来看,这有点好一点,但对于C#调用者来说可能不太明显.


kvb*_*kvb 6

我将定义一个Match成员,让代表在每个场景中执行.在F#中你会这样做(但如果需要,你可以在C#扩展方法中做同等的事情):

type Either<'a,'b> = | Left of 'a | Right of 'b
with
    member this.Match<'t>(ifLeft:System.Func<'a,'t>, ifRight:System.Func<'b,'t>) =
        match this with
        | Left a -> ifLeft.Invoke a
        | Right b -> ifRight.Invoke b
Run Code Online (Sandbox Code Playgroud)

现在你应该能够在C#中做这样的事情:

var result = a.Match(ifLeft: x => x + 1, ifRight: y => 2 * y);
Run Code Online (Sandbox Code Playgroud)