F#中的调解员动作

Woj*_*icz 2 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

调用看起来像:

Mediator.Instance.InvokeInputLogUpdate(msg);
Run Code Online (Sandbox Code Playgroud)

注册看起来像:

Mediator.Instance.InputLogUpdate += msg => this.DebugSection += $"{msg} \n";
Run Code Online (Sandbox Code Playgroud)

但是到目前为止,我所没有的是:

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)
Run Code Online (Sandbox Code Playgroud)

而且它不能很好地工作,有人知道该怎么做吗?

Fyo*_*kin 6

首先lock夹在两张null支票之间的模式过时了,我什至不记得上次看到一张支票了。现代.NET具有Lazy<T>这种按需初始化的功能。而且,幸运的是,F#实际上具有特殊的语法:

type UpdMediator private () =

    static member val private _instance = lazy UpdMediator()
    static member Instance = UpdMediator._instance.Value
Run Code Online (Sandbox Code Playgroud)

其次event Action<_>C#中的an 等同mutable Action<_>于F#。eventC#中的声明实际上会创建两个访问器方法- add和和remove- getset具有属性一样。

但是,F#实际上具有更好的机制- Event<_>。您将该类型的实例设为私有,然后通过其.Publish具有type的属性将其公开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")
Run Code Online (Sandbox Code Playgroud)

(请注意,.Subscribe返回IDisposable,可在以后取消订阅)

第三,尝试将C#实践逐字转换为F#通常效果不佳。F#通常比C#具有更好的功能,因此,如您的案例所示,逐词翻译通常会有些尴尬。

最后,请注意“不能很好地工作”不是对问题的良好描述。如果您希望收到社区的指导或建议,请花点时间描述问题的确切含义,预期会发生的情况以及如何解决该问题,等等。请参考SO“如何询问”指南以获取一些提示。