假设有一个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)
使用来自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#调用者来说可能不太明显.
我将定义一个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)
| 归档时间: |
|
| 查看次数: |
423 次 |
| 最近记录: |