使用 F# 和 Caliburn.Micro 结合使用

5
据我所知,Caliburn.Micro以一种约定式的方式,在WPF项目中执行大量自动布线和管道工作;采用MVVM模式。
问题:Caliburn.Micro中是否有任何仅限于C#使用的部分?哪些部分不能与F#代码一起使用?使用F#会失去什么?

你是否考虑使用F#编写虚拟机或其他内容?我有一个使用F#作为后端的WPF应用程序,我们使用Caliburn.Micro进行MVVM开发模式。所有我的VM都是用C#编写的。我也想知道是否可能直接从F#中使用WPF。我会尝试将其中一个VM重写成F#,并观察结果。我会让你知道的。 - Sebastian.Belczyk
@Sebastian.Belczyk 我想把所有的东西都用 F# 来写。我不喜欢混合语言的项目,它们会浪费很多精力(除了标记语言和 jQuery 之外 - 我知道 jQuery 不是一种语言)。 - Kaveh Shahbazian
我成功地拥有了 F# VM。我在循环依赖上有些困扰,但一旦解决了,就没问题了。NotifyPropertyChanged 的实现有点棘手,但你可以将其隐藏在基类中。下一步是尝试解决@PatrykĆwiek提到的问题。 - Sebastian.Belczyk
2个回答

5
很遗憾,Caliburn.Micro和F#并不兼容。
例如,Caliburn.Micro将视图视为常规类进行约定匹配(通过反射),这对于C#是正确的-视图是部分类。
F#不支持部分类,而视图仅是XAML文件。这意味着它们无法被Caliburn.Micro解析。这也意味着您将在引导程序中遇到问题,因为它将无法创建视图 - 至少没有手动使用Application.LoadComponent之类的注册。
设置引导程序也很麻烦,因为您必须在App.xaml中指定键,但由于某种原因,该键与类不匹配。 Bootstrapper 还将bool useApplication = true作为默认值传递给BootstrapperBase-而F#根据是否设置了该标志而有不同的问题,不幸的是我不记得细节了。这是因为在F#中,您自己连接入口点到应用程序,而Caliburn.Micro是构建为自动拦截该步骤。这会导致冲突......
如果您完全覆盖约定解析机制并弯曲任何IoC容器以使其按预期工作,则可以让它正常工作。在我看来,目前存在太多的摩擦。
就我个人而言,我会使用Caliburn.Micro在C#中设置应用程序的核心基础,并在F#中执行“真正的工作”。或者,我认为您甚至可以在F#项目中编写视图模型,在C#项目中编写视图,然后只需调整引导程序中约定查找的方式即可。不过,我对此方法并不完全确定,所以您需要小心谨慎。

所有看起来都像是摩擦发生在开始阶段。一旦解决了,它可能会带来更多价值(比如避免混合解决方案,从而减轻@KavehShahbazian提到的技术切换的心理负担)。如果能够在数据密集型应用程序中使用WPF和Caliburn.Micro,那将非常好,因为F#是更好的选择。 - Sebastian.Belczyk
@Sebastian.Belczyk 是的,尽管看起来可能是这样,因为我甚至没有成功地完成最初的部分。我无法确定是否还有其他可能在某些时候咬你的黑暗角落。不过我承认,如果F#和Caliburn.Micro能够一起工作,那将是很好的。 - Patryk Ćwiek

3
这是一个不错的问题。如果你决定去尝试它,请务必让我们知道实验的结果。我曾经考虑过 Caliburn 作为一个侧项目,但是并没有取得多少进展。
那么首先,你可能已经发现了以下内容:
Lambda 表达式重载的 NotifyOfPropertyChange 触发 PropertyChanged 事件的基本方法有两个重载:一个接受属性名称作为字符串,另一个接受 Lambda 表达式。后者使用巧妙的技巧 / 丑陋的 hack,从表达式体中提取属性名称。这使你在 C# 中拥有一种简洁的语法,而且在某种程度上还受到编译器的检查。
public string SomeProp
{
    get { return someField; }
    set
    {
        someField = value;
        NotifyOfPropertyChange(() => SomeProp);
    }
}

但是这种方式并不适用于 F#。你的选择要么回退到字符串方式,要么使用引号进行改进。我已经使用了类似以下代码的方式:

let notify<'a> (notifier: PropertyChangedBase) (expr: Expr<'a>) =
    let name =
        match expr with
        | PropertyGet (_, pi, _) -> pi.Name
        | _ -> failwith "Can't get property name to notify"
    notifier.NotifyOfPropertyChange(name)

这被称为:

member this.SomeProp 
    with get () = 
        someField
    and set(value) = 
        someField <- value
        notify this <@ this.SomeProp @>

我认为你可以更进一步,将其整合到你自己的PropertyChanged类中,该类建立在PropertyChangedBase之上。

谢谢,我会研究一下的。 - Kaveh Shahbazian
我花了很长时间在谷歌上搜寻这个答案的奥秘。它可以工作,但是你需要打开Microsoft.FSharp.Quotations,然后Expr和Patterns.PropertyGet将会可用。谢谢。 - Bent Tranberg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接