F# - "自填"类型属性

spi*_*kej 2 c# f#

在C#中,我可以这样:

public class A {
    ...
    private List<int> _items;
    public List<int> Items{
        get {
            if (_items == null){
                _items = DAL.FetchFromDB();
            }
            return _items;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这样,我可以实例化A类,当我要求物品时

  1. 我保证在没有明确填写列表的情况下得到它.
  2. 我避免重复调用数据库

什么是F#的等效结构?我不确定如何制作一个这样做的类型......

我不一定要求一个可变的清单; 我想知道在F#中做这样的事情的标准形式是什么,因为我只是学习语言.

Mar*_*ann 7

正如ildjarn在上述评论中指出的那样,您可以lazy以相同的方式使用关键字:

type A () =
    let items = lazy (DAL.FetchFromDB ())
    member this.Items with get () = items.Value
Run Code Online (Sandbox Code Playgroud)

然而,问题在于它是"惯用的"F#还是"良好实践"?

Items属性不是引用透明的(因为它不是确定性的),而且功能编程往往非常强调引用透明性.

当然:F#不是一种纯粹的功能语言; 它是功能第一语言.尽管如此,这意味着要充分利用它,您应该采用类似的功能优先方法来设计.

你自己的代码功能越多,你从F#获得的价值就越大.

你制作F#代码的命令,隐式或面向对象越多,你获得的代码就越少.

因此,尝试将C#逐字翻译成F#代码并不总是有意义的.你可以,但你会从中获得什么吗?

最重要的是,你可以将你的C#翻译成类似于F#的东西,但你应该考虑它是否是一个好主意.使用lazy关键字没有任何内在错误,但隐含性是我要重新考虑的事情.


Gus*_*Gus 6

这是对F#的一对一翻译:

type A() =
    let mutable _items = null
    member this.items 
        with get() = 
            if _items = null then _items <- DAL.FetchFromDB()
            _items

let a = A()

let x = a.items  // db access here
let y = a.items
Run Code Online (Sandbox Code Playgroud)

有更好(和更短)的方法在F#中使用对象编写等效代码(参见另一个答案),但你根本不需要创建一个对象,你可以简单地定义一个函数,而其他人已经指出你可以使用lazy关键字:

let items = 
    let v = lazy DAL.FetchFromDB()
    fun () -> v.Value

let x = items()  // db access here
let y = items()
Run Code Online (Sandbox Code Playgroud)

或者直接使用标准的延迟值,我更喜欢这个,因为你在类型中明确items表示你的值是惰性求值而不是隐藏在魔术对象属性或函数后面:

let items = lazy DAL.FetchFromDB()

let x = items.Value  // db access here
let y = items.Value
Run Code Online (Sandbox Code Playgroud)

所以,现在的类型items就是Lazy<'List<'T>>它总是告诉你,值将是懒惰的计算,除了在这种情况下的代码实际上是更短.