C#事件处理程序在F#中触发时未被调用

4
我很难在F#编写的类中向C#公开事件。如果使用let绑定定义事件,则没有问题:
let myFSharpEvent = new Event<EventArgs>()

[<CLIEvent>]
member this.FSharpEvent = myFSharpEvent.Publish

member this.RaiseFSharpEvent e = myFSharpEvent.Trigger e

但是,当事件被定义为私有成员时,编译是可以通过的,但在运行时添加的事件处理程序不会被执行。

member private this.myFSharpEvent = new Event<EventArgs>()

[<CLIEvent>]
member this.FSharpEvent = this.myFSharpEvent.Publish

member this.RaiseFSharpEvent e = this.myFSharpEvent.Trigger e

在C#中注册并调用事件的代码如下所示:
class Program
{
    static void Main(string[] args)
    {
        var fsObject = new FSharpClass();
        Console.WriteLine(fsObject.ToString());

        fsObject.FSharpEvent += FsObject_FSharpEvent;
        fsObject.RaiseFSharpEvent(EventArgs.Empty);
        fsObject.FSharpEvent -= FsObject_FSharpEvent;

        Console.ReadLine();
    }

    private static void FsObject_FSharpEvent(object sender, EventArgs args)
    {
        Console.WriteLine("F# event was raised.");
    }
}

然而,我找不到使用let绑定的方法,因为在我的实际场景中,我的类从一个用C#编写的类继承而来,并且不仅有一个默认构造函数,还有一个拷贝构造函数和一个反序列化构造函数需要我重写。

所以问题是:为什么let绑定可以工作,但成员private却不能。


我不理解你为什么不能使用let绑定的解释。 - Bent Tranberg
2个回答

2
我喜欢使用SharpLab.io来快速查看一些F#代码编译成C#的结果。
//Your F#
let myFSharpEvent = new Event<EventArgs>()

//To c#
internal FSharpEvent<EventArgs> myFSharpEvent;

-----------

//Your F#
member private this.myFSharpEvent = new Event<EventArgs>()

//To c#
internal FSharpEvent<EventArgs> myFSharpEvent
{
    get
    {
        return new FSharpEvent<EventArgs>();
    }
}


您可以看到,每次调用私有版本时,都会得到一个新的事件处理程序,然后将其丢弃到GC中。
我也觉得在F#中典型的面向对象编程很困惑,但我认为主要模式是使用let绑定来支持字段,并使用成员绑定进行包装。

https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/members/let-bindings-in-classes


Don Syme的一个技巧是使用疯狂的名称,以便更容易找到您要查找的有趣部分:https://sharplab.io/#v2:EYLgHgbALANANiAZgZwD4HsAOBTAdgAgGUBPZAF2wFsBYAKDOJ3wGFW22B9AS2Q+wC8OZdB2TZsACgCU+ALx18i/AqVxsZfJWIAxQgAsAhgCdMAUQBueDbPy5sAd3wWrAHme4yAQSMBzZAD5pOhVFAG0XZgAZAEl3Mn8AXRDNKmBsI3wyPR4AOl1DEzi5TR19YzNLDxyABQBXYDgePWDaJRTKNIys3IAlAx5sfPKi7GKtIcLKshyAFSMuHx90/GxkylTljhyAWWlioNalOgYmACFzi/PuXgEhETFJGRtktY2MzHnzAwpM7OQc8ZlSZWYp2RxxNxTbx+QJSFptcJRWJTRKvDrLbr/CYVEE2TEA0oFHFVOoNJrwpTrdFdP45PoDbEjYr4wFEuKzeaLZbYIA=== - EricP

1
问题在于每次访问myFsharpEvent作为成员时都会创建一个新实例。let绑定只创建一次。
因此,当您调用Trigger时,它是与您发布的不同实例,这就是为什么它在您的c#代码中引发的原因。

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