是否可以使用管道运算符来调用返回对象上的方法?

时间:2009-09-17 18:16:47

标签: f# return-value pipeline infix-notation infix-operator

是否可以使用管道中缀运算符在返回的对象上调用方法?

示例,我有一个带有方法(Method1)的.Net类(Class1)。我现在可以这样编码:

let myclass = new Class1()
let val = myclass.Method1()

我知道我也可以这样编码

let val = new Class1().Method1()

但是我想能够管道它(我在下面使用?我不知道该怎么做):

new Class1()
|> ?.Method1()

此外,假设我有一个返回一个对象的方法,我想只引用它,如果该方法没有返回null(否则保释?)

new Class1()
|> ?.Method1()
|> ?? ?.Method2()

或者为了更清楚,这里有一些C#代码:

    public void foo()
    {
        var myclass = new Class1();
        Class2 class2 = myclass.Method1();
        if (class2 == null)
        {
            return;
        }
        class2.Method2();
    }

2 个答案:

答案 0 :(得分:2)

您可以非常轻松地定义类似于(??)运算符的内容(但运算符不能以问号开头):

let (~??) f x =
  if (x <> null) then
    f x

不幸的是,你的流水线代码需要更冗长一些(同样,请注意你可以删除new关键字来调用构造函数):

Class1()
|> fun x -> x.Method1()

全部放在一起:

Class1()
|> fun x -> x.Method1()
|> ~?? (fun x -> x.Method2())

答案 1 :(得分:1)

使用自定义运算符作为'kvb'建议绝对是一种选择。在这种情况下,您可能会感兴趣的另一种方法是定义您自己的“计算表达式”,该表达式会在您指定的每个点自动执行null值的检查。使用它的代码如下所示:

open System.Windows.Forms

// this function returns (0) null, or (1) btn whose parent is 
// null or (2) button whose parent is not null
let test = function
  | 1 -> new Button(Text = "Button")
  | 2 -> new Button(Text = "Button", Parent = new Button(Text = "Parent"))
  | _ -> null

let res =  
  safe { let! btn = test(2) // specify number here for testing
         // if btn = null, this part of the computation will not execute
         // and the computation expression immediately returns null
         printfn "Text = %s" btn.Text
         let! parent = btn.Parent // safe access to parent
         printfn "Parent = %s" parent.Text // will never be null!
         return parent }

如您所见,当您想要使用可能为“null”的值时,可以在计算表达式中使用let!。可以定义计算表达式,以便在值为null时立即返回null,否则运行其余的计算。这是代码:

type SafeNullBuilder() =
  member x.Return(v) = v
  member x.Bind(v, f) = 
    if v = null then null else f(v)

let safe = new SafeNullBuilder()    
BTW:如果你想了解更多关于这一点,它与Haskell中的'Maybe'monad(或使用F#选项类型的计算)非常相似。