我有一个 .NET 库,作为对象模型的一部分,它会发出某些事件的通知。
在我看来 的主要优点事件 对于初学者来说是平易近人的(并且在某些消费环境中很简单),主要的负面影响是它们not composable因此立即被迫进入 Observable.FromEvent * 如果您想在不编写代码丛林的情况下做任何有趣的事情。
正在解决的问题的性质是,事件流量不会特别频繁或大量(绝对不是尖叫 RX),但绝对不需要支持 4.0 之前的 .NET 版本[因此我可以使用内置IObservable接口(interface)在 System.Reactive不强制对消费者产生任何重大依赖]。我对一些一般准则感兴趣,一些特定的具体原因更喜欢 IObservables在 event不过,从 API 设计的角度来看 - 无论我的具体案例可能位于 event 的哪个位置- IObservable光谱。
所以,问题:
如果我采用最简单的方法并公开 event,那么对于 API 使用者来说,有什么具体的事情我会变得更加困难或有问题吗?而不是 IObservable
或者,重申:除了消费者必须做一个 Observable.FromEvent * 为了能够组合事件,真的没有一个理由喜欢 IObservable超过 event在 API 中公开通知时?
使用项目的引用 IObservable对于不尖叫 RX 的东西或编码指南将是理想的,但并不重要。
NB 在@Adam Houldsworth 的评论中提到,我对 .NET 4+ 库的 API 表面的具体事物感兴趣,而不是关于哪个代表我们时代更好的“默认架构”的意见调查: )
注意此问题已在 IObserver and IObservable in C# for Observer vs Delegates, Events 中提及和 IObservable vs Plain Events or Why Should I use IObservable? .由于违反了 SRP,我所提出的问题的任何方面都没有在任何回复中得到解决。另一个稍微重叠的问题是 Advantages of .NET Rx over classic events? . (使用 IObservable 而不是事件)[ Use of IObservable instead of events属于同一类别。
最佳答案
在这个答案的评论中,OP 将他的问题提炼为:
[Is it] indeed definitely the case that each and every event can always be Adapted to be an
IObservable?
OnNext调用。 Observable.FromEventPattern 辅助方法在这方面做得很好,重载返回 IObservable<EventPattern<T>>提供发件人对象和 EventArgs .Observable Stream = { OnNext }, [ OnError | OnCompleted ] - 或 0 个或多个 OnNext 事件,可选地后跟 OnCompleted 或 OnError。The notion of raising an event is precisely equivalent to invoking the delegate represented by the event—thus, there are no special language constructs for raising events.
When an event has multiple subscribers, the event handlers are invoked synchronously when an event is raised. To invoke events asynchronously, see Calling Synchronous Methods Asynchronously.
4.2. Assume observer instances are called in a serialized fashion
请注意,此语句仅针对单个订阅者实例的观点,而没有提及跨实例并发发送的事件(这实际上在 Rx 中非常常见)。
所以有两条路:虽然 OnNext捕捉事件的想法 经典的 .NET 事件可能会通过并发调用事件来违反 Rx 语法。纯 Rx Observables 在负载下的事件传递有不同的语义是很常见的,因为背压通常是按订阅者而不是按事件处理的。
只要您不在 API 中同时引发事件,并且您不关心背压语义,然后通过像 Rx 的Observable.FromEvent之类的机制转换为可观察的接口(interface)会没事的。
逆变换
关于逆变换,注意OnError和OnCompleted在经典的 .NET 事件中没有类似物,因此如果没有一些额外的机制和约定的用法,就不可能进行反向映射。
例如,可以翻译OnError和OnCompleted到其他事件 - 但这绝对超出了经典事件领域。此外,在不同的处理程序之间需要一些非常笨拙的同步机制;在 Rx 中,一个订阅者很可能收到OnCompleted而另一个仍在接收OnNext事件 - 在经典的 .NET 事件转换中实现这一点要困难得多。
错误
考虑错误情况下的行为:将事件源中的错误与处理程序/订阅者中的错误区分开来很重要。OnError有没有处理前者,在后一种情况下,经典事件和 Rx 都简单地(并且正确地)爆炸了。这方面的错误确实可以在任一方向上很好地转化。
结论
.NET 经典事件和 Observable 不是同构的。只要您坚持正常的使用模式,您就可以相当容易地从事件转换为可观察的。可能的情况是,您的 API 需要使用 .NET 事件建模的 observables 的附加语义,因此仅使用 Observable 更有意义 - 但这是一个特定的考虑因素,而不是一般的考虑因素,更多的是一种设计问题比技术问题。
作为一般指导,我建议尽可能优先选择经典事件,因为这些事件被广泛理解并得到很好的支持并且可以转换 - 但如果您需要以优雅形式表示的源错误或完成的额外语义,请不要犹豫使用可观察对象OnError 和 OnCompleted 事件。
关于c# - 在面向 .NET 4+ 的库中公开通知时,IObservable 是否应该优先于事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24572366/
作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou
如何在ruby中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL
我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha
我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur
是否有简单的方法来更改默认ISO格式(yyyy-mm-dd)的ActiveAdmin日期过滤器显示格式? 最佳答案 您可以像这样为日期选择器提供额外的选项,而不是覆盖js:=f.input:my_date,as::datepicker,datepicker_options:{dateFormat:"mm/dd/yy"} 关于ruby-on-rails-事件管理员日期过滤器日期格式自定义,我们在StackOverflow上找到一个类似的问题: https://s
如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.
1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里