C# 从非标准事件创建可观察事件(无EventArgs/EventHandler)

C# 从非标准事件创建可观察事件(无EventArgs/EventHandler),c#,.net,events,observable,system.reactive,C#,.net,Events,Observable,System.reactive,我想为定义如下的事件创建一个可观察的事件: public event Func<Exception, Task> Closed; 公共事件功能关闭; 我目前的代码是: Observable.FromEvent<Func<Exception, Task>, Unit>(h => hub.Closed += h, h=> hub.Closed -= h); Observable.FromEvent(h=>hub.Closed+=h,h=>hub

我想为定义如下的事件创建一个可观察的事件:

public event Func<Exception, Task> Closed;
公共事件功能关闭;
我目前的代码是:

Observable.FromEvent<Func<Exception, Task>, Unit>(h => hub.Closed += h, h=> hub.Closed -= h); 
Observable.FromEvent(h=>hub.Closed+=h,h=>hub.Closed-=h);
它编译正常,但会引发以下运行时异常:

System.ArgumentException:'无法绑定到目标方法,因为 其签名或安全透明度与 委托类型为“”


我觉得我做错了。我不习惯从不遵循EventArgs模式的事件中创建可观察对象,请尝试以下操作,不要使用您想要的签名,而是尝试一些东西:

class Program
{
        public delegate void ClosedEventHandler(object sender, Func<Exception, Task> e);
        public ClosedEventHandler Closed { get; set; }    

        static void Main(string[] args)
        {
            Program hub = new Program();
            hub.Closed = hub.SomethingToDoWhenClosed;    
            Observable
                .FromEventPattern<ClosedEventHandler, Func<Exception, Task>>(
                    h => hub.Closed += h,
                    h => hub.Closed -= h)
                .Subscribe(x =>
                {
                    // this is hit
                });    
            hub.Closed(hub, e => null);
        }

        public void SomethingToDoWhenClosed(object sender, Func<Exception, Task> e)
        {
        }
}
类程序
{
公共委托void ClosedEventHandler(对象发送方,函数e);
public ClosedEventHandler Closed{get;set;}
静态void Main(字符串[]参数)
{
程序中心=新程序();
hub.Closed=hub.something到dowhenclosed;
可观察
.FromEventPattern(
h=>hub.Closed+=h,
h=>hub.Closed-=h)
.订阅(x=>
{
//这被击中了
});    
hub.Closed(hub,e=>null);
}
public void something todowhenclosed(对象发送方,函数e)
{
}
}

像这样的东西能奏效吗

class Program
{
    public event Func<Exception, Task> Closed;

    static void Main(string[] args)
    {
        Program p = new Program();
        IObservable<Unit> closedObservable = Observable.Create<Unit>(
            observer =>
            {
                Func<Exception, Task> handler = ex =>
                {
                    observer.OnNext(Unit.Default);
                    return Task.CompletedTask;
                };

                p.Closed += handler;

                return () => p.Closed -= handler;
            });
    }
}
类程序
{
公共活动关闭;
静态void Main(字符串[]参数)
{
程序p=新程序();
IObservable closedObservable=可观察。创建(
观察员=>
{
Func handler=ex=>
{
observer.OnNext(默认单位);
返回Task.CompletedTask;
};
p、 闭合+=处理器;
return()=>p.Closed-=handler;
});
}
}
Observable.Create()
对于此类异常情况是一种有用的后备方法


顺便说一句,有一个带有非void返回委托的事件是非常奇怪的,因为引发事件的代码只能看到最后一个要运行的处理程序的值——除非它以某种非标准方式引发事件。但是,既然它是库代码,那就不用你管了

您需要转换重载。每次我查这个东西的时候我都会快门:

IObservable<TEventArgs> Observable.FromEvent<TDelegate, TEventArgs>(
    Func<Action<TEventArgs>, TDelegate> conversion, 
    Action<TDelegate> addHandler, 
    Action<TDelegate> removeHandler>
)

public委托void ClosedEventHandler(对象发送方,函数)这不会编译错误,消息格式不正确。我已经编辑了它,现在代码显示为OK。我要试试。使用不起作用的链接,返回的主要位置在哪里。对不起,我忘了返回任务,但添加了一个返回任务。例如,完成不会更改任何内容。它不会编译。您还可以等待Observable.FirstAsync。它不会编译,上面显示的代码在VS2017上为我运行,并且能够调试到订阅中。我认为,一旦你添加了额外的异步代码,这是很奇怪的。你能举一个例子,用传统的事件处理代码来使用你的事件吗?这将使它更容易被观察到。谢谢@Enigmativity。我正在使用来自第三方库(SignalR Core)的已关闭事件。事件定义如下:我正在尝试的代码在此repo中:。请随意克隆它。这真的很简单。同时运行服务器和客户端,您将得到异常。@Enigmativity我刚刚添加了带有经典事件处理的代码。我希望这足够了。这让我头疼:)非常感谢!也许这是可行的,但我宁愿使用
Observable.FromEvent
Observable.FromEventPattern
来实现这一点。我怀疑
Create
方法在这里是否合理。我希望你能理解。我知道你是从哪里来的,但我怀疑代理是
Func
而不是
Action
这一事实是非常不寻常的,Rx根本不允许这样做。传统上,它会被认为是“坏的”,尽管我相信信号机开发者对此有很好的理由;-)哦,乍一看,这看起来是个糟糕的设计决定?另外,如果我很了解您的话,问题在于代理的签名是
Func
,而不是
操作,对吗?没错。我快速查看了您引用的信号器代码,看起来他们似乎在等待返回的任务执行错误日志记录,但是,如果我理解正确,他们将只对其中一个事件处理程序执行此操作。来源:当委托调用的方法的签名包含返回值时,委托将返回调用列表中最后一个元素的返回值
class Program
{
    static async Task Main(string[] args)
    {

        Program.Closed += Program.HubOnClosed;
        Observable.FromEvent<Func<Exception, Task>, Exception>(
            a => e => {a(e); return Task.CompletedTask; }, 
            h => Program.Closed += h, 
            h => Program.Closed -= h
        )
            .Subscribe(e =>
            {
                Console.WriteLine("Rx: The connection to the hub has been closed");
            });

        Program.Closed.Invoke(null);
        Program.Closed.Invoke(null);
    }

    private static Task HubOnClosed(Exception arg)
    {
        Console.WriteLine("The connection to the hub has been closed");
        return Task.CompletedTask;
    }

    public static event Func<Exception, Task> Closed;
}