首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >从非标准事件创建可观察的事件(没有EventArgs / EventHandler)

从非标准事件创建可观察的事件(没有EventArgs / EventHandler)
EN

Stack Overflow用户
提问于 2018-09-26 09:04:08
回答 3查看 662关注 0票数 3

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

代码语言:javascript
运行
复制
public event Func<Exception, Task> Closed;

我目前的代码是:

代码语言:javascript
运行
复制
Observable.FromEvent<Func<Exception, Task>, Unit>(h => hub.Closed += h, h=> hub.Closed -= h); 

它编译OK,但它抛出这个运行时异常:

System.ArgumentException:“无法绑定到目标方法,因为它的签名或安全性透明度与委托类型不兼容。”

我觉得我做错了。我不习惯从不遵循EventArgs模式的事件中创建可观察的

编辑:只是为了澄清起见,这是完整的代码,其中包含了经典事件处理的外观:

代码语言:javascript
运行
复制
class Program
{
    static async Task Main(string[] args)
    {
        var hub = new HubConnectionBuilder().WithUrl("http://localhost:49791/hubs/status")
            .Build();

        hub.On<Status>("SendAction", status => Console.WriteLine($"Altitude: {status.Altitude:F} m"));
        await hub.StartAsync();

        hub.Closed += HubOnClosed;

        while (true)
        {
        }
    }

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

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-09-26 17:32:44

你需要转换过载。每次我查到这个东西时我都会快门:

代码语言:javascript
运行
复制
IObservable<TEventArgs> Observable.FromEvent<TDelegate, TEventArgs>(
    Func<Action<TEventArgs>, TDelegate> conversion, 
    Action<TDelegate> addHandler, 
    Action<TDelegate> removeHandler>
)

所以在我们的例子中,TEventArgsExceptionTDelegateFunc<Exception, Task>,所以您需要将Action<Exception>转换为Func<Exception, Task>>,换句话说:Func<Action<Exception>, Func<Exception, Task>>。我假设转换如下:a => e => {a(e); return Task.CompletedTask; }

System.Reactive需要此转换函数,因为它需要使用适当的委托订阅事件,并以某种方式将代码/RX管道代码挂钩。在本例中,a(e)基本上是RX管道,然后传递将在反应管道中处理的异常。

完整代码:

代码语言:javascript
运行
复制
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;
}
票数 9
EN

Stack Overflow用户

发布于 2018-09-26 14:00:26

像这样的东西能起作用吗?

代码语言:javascript
运行
复制
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;
            });
    }
}

对于这种不寻常的情况,Observable.Create()是一个有用的后盾。

顺便说一下,有一个具有非空返回委托的事件非常奇怪,因为引发该事件的代码只会看到要运行的最后一个处理程序的值--除非它以某种非标准的方式引发该事件。但是,既然这是图书馆的代码,那是你无法控制的!

票数 2
EN

Stack Overflow用户

发布于 2018-09-26 09:58:37

尝试以下操作,而不是使用您想要的签名,而是尝试一些东西:

代码语言:javascript
运行
复制
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)
        {
        }
}
票数 -2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52513886

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档