f# - F# 中的中介操作

标签 f#

我有一个问题,我正在尝试基于 f# 中的 singelton 创建某种调解器。主要原因是我需要在我的应用程序的一部分中注册一些操作并在另一个类似于 c# 的部分中执行它,如下所示:

public class Mediator
{
    private static readonly object syncRoot = new object();
    private static Mediator instance;

    public static Mediator Instance
    {
        get
        {
            if (instance == null)
            {
                lock (syncRoot)
                {
                    if (instance == null)
                    {
                        instance = new Mediator();
                    }
                }
            }

            return instance;
        }
    }

    public event Action<string> InputLogUpdate;
    public void InvokeInputLogUpdate(string msg)
    {
        InputLogUpdate?.Invoke(msg);
    }
}

调用看起来像:
Mediator.Instance.InvokeInputLogUpdate(msg);

注册看起来像:
Mediator.Instance.InputLogUpdate += msg => this.DebugSection += $"{msg} \n";

但就目前而言,没有运气,我所拥有的只是:
vnamespace Operation.Mediator

module Mediator = 
open System
type UdpMediator private () =

    static let instance = UdpMediator()
    let mutable UpdateDebigLog : Action<string> = null

    static member Instance = instance
    member this.InvokeUpdateLog (msg:string) = UpdateDebigLog.Invoke(msg)

而且效果不是很好,有人知道怎么做吗?

最佳答案

第一 , lock 的模式夹在两个 null 之间支票太陈旧了,我什至不记得我最后一次看到它是什么时候了。现代 .NET 有 Lazy<T>对于这种按需初始化。而且,幸运的是,F# 实际上有它的特殊语法:

type UpdMediator private () =

    static member val private _instance = lazy UpdMediator()
    static member Instance = UpdMediator._instance.Value

第二 , 一个 event Action<_>在 C# 中不等于 mutable Action<_>在 F# 中。一个 event C# 中的声明实际上创建了两个访问器方法 - addremove , - 就像 getset与属性。

不过,F#其实有更好的机制——Event<_> .您将该类型的实例设为私有(private),然后通过它的.Publish 公开它。属性,类型为 IEvent<_> .消费者可以使用 IEvent添加和删​​除处理程序的值,或订阅可观察样式的事件(因为 IEvent 继承自 IObservable ):
type UpdMediator private () =
    ...

    member val private _updDebugLog = Event<string>()
    member this.UpdDebugLog = this._updDebugLog.Publish

    member this.InvokeUpdDebugLog() = this._updDebugLog.Trigger "foo"


// usage:
UpdMediator.Instance.UpdDebugLog.AddHandler (fun sender str -> printfn "%s" str)

// Or observable-style:
UpdMediator.Instance.UpdDebugLog.Subscribe (printfn "%s")

(注意 .Subscribe 返回一个 IDisposable ,以后可以用来取消订阅)

第三 ,尝试将 C# 实践逐字翻译成 F# 通常不会有好的结果。 F# 通常比 C# 具有更好的功能,因此如您的案例所示,逐字翻译通常会有点尴尬。

最后,请注意,“不能很好地工作”并不是对问题的良好描述。如果您希望从社区中获得指导或建议,请花时间描述问题的具体内容、您预期会发生什么、您如何尝试实现它等等。请引用the SO "How to Ask" guide一些提示。

关于f# - F# 中的中介操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57758150/

相关文章:

f# - FSharp 在基类中调用泛型方法

f# - 将 OCaml 转换为 F# : Converting OCaml quotation add and quotation expander to F#

f# - 如何为旧版 F# 应用程序提供 ResizeArray?

f# - 从文本文件中读取并排序

f# - 如何在 F# 中定义常量文字

f# - FSharp.Core中未记录的 `when`关键字用法

compiler-errors - 将内联与显式成员约束结合时出现奇怪的错误

f# - 在 F# 中创建并使用函数注册表

.net - F# printfn "%A"到剪贴板

.net - 不能将 try/与序列表达式内的 block 一起使用。如何绕过它?