FromEventPatternTest.cs 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT License.
  3. // See the LICENSE file in the project root for more information.
  4. using System;
  5. using System.Collections.Generic;
  6. using System.ComponentModel;
  7. using System.Diagnostics;
  8. using System.Linq;
  9. using System.Reactive;
  10. using System.Reactive.Concurrency;
  11. using System.Reactive.Linq;
  12. using System.Reflection;
  13. using System.Threading;
  14. using Microsoft.Reactive.Testing;
  15. using Microsoft.VisualStudio.TestTools.UnitTesting;
  16. using Assert = Xunit.Assert;
  17. namespace ReactiveTests.Tests
  18. {
  19. [TestClass]
  20. public class FromEventPatternTest : ReactiveTest
  21. {
  22. #region Strongly typed
  23. [TestMethod]
  24. public void FromEventPattern_Conversion_ArgumentChecking()
  25. {
  26. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEventPattern(null, h => { }));
  27. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEventPattern(h => { }, null));
  28. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEventPattern(null, h => { }, Scheduler.Default));
  29. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEventPattern(h => { }, null, Scheduler.Default));
  30. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEventPattern(h => { }, h => { }, default));
  31. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEventPattern<EventHandler, EventArgs>(null, h => { }, h => { }));
  32. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEventPattern<EventHandler, EventArgs>(h => new EventHandler(h), null, h => { }));
  33. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEventPattern<EventHandler, EventArgs>(h => new EventHandler(h), h => { }, null));
  34. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEventPattern<EventHandler, EventArgs>(null, h => { }, h => { }, Scheduler.Default));
  35. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEventPattern<EventHandler, EventArgs>(h => new EventHandler(h), null, h => { }, Scheduler.Default));
  36. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEventPattern<EventHandler, EventArgs>(h => new EventHandler(h), h => { }, null, Scheduler.Default));
  37. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEventPattern<EventHandler, EventArgs>(h => new EventHandler(h), h => { }, h => { }, default));
  38. }
  39. [TestMethod]
  40. public void FromEventPattern_E2()
  41. {
  42. var scheduler = new TestScheduler();
  43. var fe = new FromEventPattern();
  44. scheduler.ScheduleAbsolute(50, () => fe.M2(1));
  45. scheduler.ScheduleAbsolute(150, () => fe.M2(2));
  46. scheduler.ScheduleAbsolute(250, () => fe.M2(3));
  47. scheduler.ScheduleAbsolute(350, () => fe.M2(4));
  48. scheduler.ScheduleAbsolute(450, () => fe.M2(5));
  49. scheduler.ScheduleAbsolute(1050, () => fe.M2(6));
  50. var results = scheduler.Start(() =>
  51. Observable.FromEventPattern<EventHandler<FromEventPattern.TestEventArgs>, FromEventPattern.TestEventArgs>(
  52. h => fe.E2 += h,
  53. h => fe.E2 -= h)
  54. .Select(evt => new { evt.Sender, evt.EventArgs }));
  55. results.Messages.AssertEqual(
  56. OnNext(250, new { Sender = (object)fe, EventArgs = new FromEventPattern.TestEventArgs { Id = 3 } }),
  57. OnNext(350, new { Sender = (object)fe, EventArgs = new FromEventPattern.TestEventArgs { Id = 4 } }),
  58. OnNext(450, new { Sender = (object)fe, EventArgs = new FromEventPattern.TestEventArgs { Id = 5 } })
  59. );
  60. }
  61. [TestMethod]
  62. public void FromEventPattern_Conversion_E4()
  63. {
  64. var scheduler = new TestScheduler();
  65. var fe = new FromEventPattern();
  66. scheduler.ScheduleAbsolute(50, () => fe.M4(1));
  67. scheduler.ScheduleAbsolute(150, () => fe.M4(2));
  68. scheduler.ScheduleAbsolute(250, () => fe.M4(3));
  69. scheduler.ScheduleAbsolute(350, () => fe.M4(4));
  70. scheduler.ScheduleAbsolute(450, () => fe.M4(5));
  71. scheduler.ScheduleAbsolute(1050, () => fe.M4(6));
  72. var results = scheduler.Start(() =>
  73. Observable.FromEventPattern<Action<int>, FromEventPattern.TestEventArgs>(
  74. h => new Action<int>(x => h(fe, new FromEventPattern.TestEventArgs { Id = x })),
  75. h => fe.E4 += h,
  76. h => fe.E4 -= h)
  77. .Select(evt => new { evt.Sender, evt.EventArgs }));
  78. results.Messages.AssertEqual(
  79. OnNext(250, new { Sender = (object)fe, EventArgs = new FromEventPattern.TestEventArgs { Id = 3 } }),
  80. OnNext(350, new { Sender = (object)fe, EventArgs = new FromEventPattern.TestEventArgs { Id = 4 } }),
  81. OnNext(450, new { Sender = (object)fe, EventArgs = new FromEventPattern.TestEventArgs { Id = 5 } })
  82. );
  83. }
  84. [TestMethod]
  85. public void FromEventPattern_Conversion_E5()
  86. {
  87. var scheduler = new TestScheduler();
  88. var fe = new FromEventPattern();
  89. scheduler.ScheduleAbsolute(50, () => fe.M5(1));
  90. scheduler.ScheduleAbsolute(150, () => fe.M5(2));
  91. scheduler.ScheduleAbsolute(250, () => fe.M5(3));
  92. scheduler.ScheduleAbsolute(350, () => fe.M5(4));
  93. scheduler.ScheduleAbsolute(450, () => fe.M5(5));
  94. scheduler.ScheduleAbsolute(1050, () => fe.M5(6));
  95. var results = scheduler.Start(() =>
  96. Observable.FromEventPattern(
  97. h => fe.E5 += h,
  98. h => fe.E5 -= h)
  99. .Select(evt => new { evt.Sender, EventArgs = (FromEventPattern.TestEventArgs)evt.EventArgs }));
  100. results.Messages.AssertEqual(
  101. OnNext(250, new { Sender = (object)fe, EventArgs = new FromEventPattern.TestEventArgs { Id = 3 } }),
  102. OnNext(350, new { Sender = (object)fe, EventArgs = new FromEventPattern.TestEventArgs { Id = 4 } }),
  103. OnNext(450, new { Sender = (object)fe, EventArgs = new FromEventPattern.TestEventArgs { Id = 5 } })
  104. );
  105. }
  106. [TestMethod]
  107. public void FromEventPattern_ConversionThrows()
  108. {
  109. var ex = new Exception();
  110. var fe = new FromEventPattern();
  111. var res =
  112. Observable.FromEventPattern<Action<int>, FromEventPattern.TestEventArgs>(
  113. h => { throw ex; },
  114. h => fe.E4 += h,
  115. h => fe.E4 -= h
  116. );
  117. var err = default(Exception);
  118. res.Subscribe(_ => { Assert.True(false); }, ex_ => err = ex_, () => { Assert.True(false); });
  119. Assert.Same(ex, err);
  120. }
  121. [TestMethod]
  122. public void FromEventPattern_E2_WithSender()
  123. {
  124. var scheduler = new TestScheduler();
  125. var fe = new FromEventPattern();
  126. scheduler.ScheduleAbsolute(50, () => fe.M2(1));
  127. scheduler.ScheduleAbsolute(150, () => fe.M2(2));
  128. scheduler.ScheduleAbsolute(250, () => fe.M2(3));
  129. scheduler.ScheduleAbsolute(350, () => fe.M2(4));
  130. scheduler.ScheduleAbsolute(450, () => fe.M2(5));
  131. scheduler.ScheduleAbsolute(1050, () => fe.M2(6));
  132. var results = scheduler.Start(() =>
  133. Observable.FromEventPattern<EventHandler<FromEventPattern.TestEventArgs>, object, FromEventPattern.TestEventArgs>(
  134. h => fe.E2 += h,
  135. h => fe.E2 -= h)
  136. .Select(evt => new { evt.Sender, evt.EventArgs }));
  137. results.Messages.AssertEqual(
  138. OnNext(250, new { Sender = (object)fe, EventArgs = new FromEventPattern.TestEventArgs { Id = 3 } }),
  139. OnNext(350, new { Sender = (object)fe, EventArgs = new FromEventPattern.TestEventArgs { Id = 4 } }),
  140. OnNext(450, new { Sender = (object)fe, EventArgs = new FromEventPattern.TestEventArgs { Id = 5 } })
  141. );
  142. }
  143. [TestMethod]
  144. public void FromEventPattern_AddRemove_ArgumentChecking()
  145. {
  146. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEventPattern<EventArgs>(null, h => { }));
  147. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEventPattern<EventArgs>(h => { }, null));
  148. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEventPattern<EventHandler, EventArgs>(null, h => { }));
  149. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEventPattern<EventHandler, EventArgs>(h => { }, null));
  150. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEventPattern<EventHandler, object, EventArgs>(null, h => { }));
  151. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEventPattern<EventHandler, object, EventArgs>(h => { }, null));
  152. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEventPattern<EventArgs>(null, h => { }, Scheduler.Default));
  153. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEventPattern<EventArgs>(h => { }, null, Scheduler.Default));
  154. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEventPattern<EventArgs>(h => { }, h => { }, default));
  155. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEventPattern<EventHandler, EventArgs>(null, h => { }, Scheduler.Default));
  156. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEventPattern<EventHandler, EventArgs>(h => { }, null, Scheduler.Default));
  157. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEventPattern<EventHandler, EventArgs>(h => { }, h => { }, default));
  158. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEventPattern<EventHandler, object, EventArgs>(null, h => { }, Scheduler.Default));
  159. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEventPattern<EventHandler, object, EventArgs>(h => { }, null, Scheduler.Default));
  160. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEventPattern<EventHandler, object, EventArgs>(h => { }, h => { }, default));
  161. }
  162. [TestMethod]
  163. public void FromEventPattern_AddRemove_E4()
  164. {
  165. var scheduler = new TestScheduler();
  166. var fe = new FromEventPattern();
  167. scheduler.ScheduleAbsolute(50, () => fe.M2(1));
  168. scheduler.ScheduleAbsolute(150, () => fe.M2(2));
  169. scheduler.ScheduleAbsolute(250, () => fe.M2(3));
  170. scheduler.ScheduleAbsolute(350, () => fe.M2(4));
  171. scheduler.ScheduleAbsolute(450, () => fe.M2(5));
  172. scheduler.ScheduleAbsolute(1050, () => fe.M2(6));
  173. var results = scheduler.Start(() =>
  174. Observable.FromEventPattern<FromEventPattern.TestEventArgs>(
  175. h => fe.E2 += h,
  176. h => fe.E2 -= h)
  177. .Select(evt => new { evt.Sender, evt.EventArgs }));
  178. results.Messages.AssertEqual(
  179. OnNext(250, new { Sender = (object)fe, EventArgs = new FromEventPattern.TestEventArgs { Id = 3 } }),
  180. OnNext(350, new { Sender = (object)fe, EventArgs = new FromEventPattern.TestEventArgs { Id = 4 } }),
  181. OnNext(450, new { Sender = (object)fe, EventArgs = new FromEventPattern.TestEventArgs { Id = 5 } })
  182. );
  183. }
  184. #endregion
  185. #region Reflection
  186. #region Instance events
  187. [TestMethod]
  188. public void FromEventPattern_Reflection_Instance_ArgumentChecking()
  189. {
  190. ReactiveAssert.Throws</**/ArgumentNullException>(() => Observable.FromEventPattern(default(object), "foo"));
  191. ReactiveAssert.Throws</**/ArgumentNullException>(() => Observable.FromEventPattern(new FromEventPattern_ArgCheck(), null));
  192. ReactiveAssert.Throws</**/ArgumentNullException>(() => Observable.FromEventPattern(default(object), "foo", Scheduler.Default));
  193. ReactiveAssert.Throws</**/ArgumentNullException>(() => Observable.FromEventPattern(new FromEventPattern_ArgCheck(), null, Scheduler.Default));
  194. ReactiveAssert.Throws</**/ArgumentNullException>(() => Observable.FromEventPattern(new FromEventPattern_ArgCheck(), "foo", default));
  195. ReactiveAssert.Throws<InvalidOperationException>(() => Observable.FromEventPattern(new FromEventPattern_ArgCheck(), "E1"));
  196. ReactiveAssert.Throws<InvalidOperationException>(() => Observable.FromEventPattern(new FromEventPattern_ArgCheck(), "E5"));
  197. ReactiveAssert.Throws<InvalidOperationException>(() => Observable.FromEventPattern(new FromEventPattern_ArgCheck(), "E6"));
  198. ReactiveAssert.Throws<InvalidOperationException>(() => Observable.FromEventPattern(new FromEventPattern_ArgCheck(), "foo"));
  199. ReactiveAssert.Throws</**/ArgumentNullException>(() => Observable.FromEventPattern<EventArgs>(default(object), "foo"));
  200. ReactiveAssert.Throws</**/ArgumentNullException>(() => Observable.FromEventPattern<EventArgs>(new FromEventPattern_ArgCheck(), null));
  201. ReactiveAssert.Throws</**/ArgumentNullException>(() => Observable.FromEventPattern<EventArgs>(default(object), "foo", Scheduler.Default));
  202. ReactiveAssert.Throws</**/ArgumentNullException>(() => Observable.FromEventPattern<EventArgs>(new FromEventPattern_ArgCheck(), null, Scheduler.Default));
  203. ReactiveAssert.Throws</**/ArgumentNullException>(() => Observable.FromEventPattern<EventArgs>(new FromEventPattern_ArgCheck(), "foo", default));
  204. ReactiveAssert.Throws<InvalidOperationException>(() => Observable.FromEventPattern<EventArgs>(new FromEventPattern_ArgCheck(), "E1"));
  205. ReactiveAssert.Throws<InvalidOperationException>(() => Observable.FromEventPattern<EventArgs>(new FromEventPattern_ArgCheck(), "E2"));
  206. ReactiveAssert.Throws<InvalidOperationException>(() => Observable.FromEventPattern<EventArgs>(new FromEventPattern_ArgCheck(), "E3"));
  207. ReactiveAssert.Throws<InvalidOperationException>(() => Observable.FromEventPattern<EventArgs>(new FromEventPattern_ArgCheck(), "E4"));
  208. ReactiveAssert.Throws<InvalidOperationException>(() => Observable.FromEventPattern<EventArgs>(new FromEventPattern_ArgCheck(), "E5"));
  209. ReactiveAssert.Throws<InvalidOperationException>(() => Observable.FromEventPattern<EventArgs>(new FromEventPattern_ArgCheck(), "E6"));
  210. ReactiveAssert.Throws<InvalidOperationException>(() => Observable.FromEventPattern<EventArgs>(new FromEventPattern_ArgCheck(), "foo"));
  211. ReactiveAssert.Throws</**/ArgumentNullException>(() => Observable.FromEventPattern<FromEventPattern_ArgCheck, EventArgs>(default(object), "foo"));
  212. ReactiveAssert.Throws</**/ArgumentNullException>(() => Observable.FromEventPattern<FromEventPattern_ArgCheck, EventArgs>(new FromEventPattern_ArgCheck(), null));
  213. ReactiveAssert.Throws</**/ArgumentNullException>(() => Observable.FromEventPattern<FromEventPattern_ArgCheck, EventArgs>(default(object), "foo", Scheduler.Default));
  214. ReactiveAssert.Throws</**/ArgumentNullException>(() => Observable.FromEventPattern<FromEventPattern_ArgCheck, EventArgs>(new FromEventPattern_ArgCheck(), null, Scheduler.Default));
  215. ReactiveAssert.Throws</**/ArgumentNullException>(() => Observable.FromEventPattern<FromEventPattern_ArgCheck, EventArgs>(new FromEventPattern_ArgCheck(), "foo", default));
  216. ReactiveAssert.Throws<InvalidOperationException>(() => Observable.FromEventPattern<FromEventPattern_ArgCheck, EventArgs>(new FromEventPattern_ArgCheck(), "E1"));
  217. ReactiveAssert.Throws<InvalidOperationException>(() => Observable.FromEventPattern<FromEventPattern_ArgCheck, EventArgs>(new FromEventPattern_ArgCheck(), "E2"));
  218. ReactiveAssert.Throws<InvalidOperationException>(() => Observable.FromEventPattern<FromEventPattern_ArgCheck, EventArgs>(new FromEventPattern_ArgCheck(), "E3"));
  219. ReactiveAssert.Throws<InvalidOperationException>(() => Observable.FromEventPattern<FromEventPattern_ArgCheck, EventArgs>(new FromEventPattern_ArgCheck(), "E4"));
  220. ReactiveAssert.Throws<InvalidOperationException>(() => Observable.FromEventPattern<FromEventPattern_ArgCheck, EventArgs>(new FromEventPattern_ArgCheck(), "E5"));
  221. ReactiveAssert.Throws<InvalidOperationException>(() => Observable.FromEventPattern<FromEventPattern_ArgCheck, EventArgs>(new FromEventPattern_ArgCheck(), "E6"));
  222. ReactiveAssert.Throws<InvalidOperationException>(() => Observable.FromEventPattern<FromEventPattern_ArgCheck, EventArgs>(new FromEventPattern_ArgCheck(), "foo"));
  223. }
  224. [TestMethod]
  225. public void FromEventPattern_Reflection_Instance_InvalidVariance()
  226. {
  227. ReactiveAssert.Throws<InvalidOperationException>(() => Observable.FromEventPattern<CancelEventArgs>(new FromEventPattern_VarianceCheck(), "E1"));
  228. }
  229. [TestMethod]
  230. public void FromEventPattern_Reflection_Instance_VarianceArgs()
  231. {
  232. var src = new FromEventPattern_VarianceCheck();
  233. var es = Observable.FromEventPattern<EventArgs>(src, "E2");
  234. var e1 = new CancelEventArgs();
  235. var e2 = new CancelEventArgs();
  236. var lst = new List<EventPattern<EventArgs>>();
  237. using (es.Subscribe(e => lst.Add(e)))
  238. {
  239. src.OnE2(e1);
  240. src.OnE2(e2);
  241. }
  242. src.OnE2(new CancelEventArgs());
  243. Assert.True(lst.Count == 2, "Count");
  244. Assert.True(ReferenceEquals(e1, lst[0].EventArgs), "First");
  245. Assert.True(ReferenceEquals(e2, lst[1].EventArgs), "Second");
  246. }
  247. [TestMethod]
  248. public void FromEventPattern_Reflection_Instance_VarianceSender()
  249. {
  250. var src = new FromEventPattern_VarianceCheck();
  251. var es = Observable.FromEventPattern<EventArgs>(src, "E3");
  252. var s1 = "Hello";
  253. var s2 = "World";
  254. var lst = new List<EventPattern<EventArgs>>();
  255. using (es.Subscribe(e => lst.Add(e)))
  256. {
  257. src.OnE3(s1);
  258. src.OnE3(s2);
  259. }
  260. src.OnE3("Fail!");
  261. Assert.True(lst.Count == 2, "Count");
  262. Assert.True(ReferenceEquals(s1, lst[0].Sender), "First");
  263. Assert.True(ReferenceEquals(s2, lst[1].Sender), "Second");
  264. }
  265. [TestMethod]
  266. public void FromEventPattern_Reflection_Instance_NonGeneric()
  267. {
  268. var src = new FromEventPattern_VarianceCheck();
  269. var es = Observable.FromEventPattern(src, "E2");
  270. var e1 = new CancelEventArgs();
  271. var e2 = new CancelEventArgs();
  272. var lst = new List<EventPattern<object>>();
  273. using (es.Subscribe(e => lst.Add(e)))
  274. {
  275. src.OnE2(e1);
  276. src.OnE2(e2);
  277. }
  278. src.OnE2(new CancelEventArgs());
  279. Assert.True(lst.Count == 2, "Count");
  280. Assert.True(ReferenceEquals(e1, lst[0].EventArgs), "First");
  281. Assert.True(ReferenceEquals(e2, lst[1].EventArgs), "Second");
  282. }
  283. [TestMethod]
  284. public void FromEventPattern_Reflection_Instance_Throws()
  285. {
  286. //
  287. // BREAKING CHANGE v2.0 > v1.x - We no longer throw the exception synchronously as part of
  288. // the Subscribe, so it comes out through OnError now. Also,
  289. // we now unwrap TargetInvocationException objects.
  290. //
  291. var exAdd = default(Exception);
  292. var xs = Observable.FromEventPattern<FromEventPattern.TestEventArgs>(new FromEventPattern(), "AddThrows");
  293. xs.Subscribe(_ => { Assert.True(false); }, ex => exAdd = ex, () => { Assert.True(false); });
  294. Assert.True(exAdd is InvalidOperationException);
  295. //
  296. // Notice the exception propgation behavior is asymmetric by design. Below, the Dispose
  297. // call will throw synchronously, merely because we happen to use FromEventPattern from a
  298. // thread with no SynchronizationContext, causing the Immediate scheduler to be used.
  299. //
  300. // See AddHandler in FromEvent.cs for more information on the design rationale of the
  301. // asymmetry you see here.
  302. //
  303. var exRem = default(Exception);
  304. var ys = Observable.FromEventPattern<FromEventPattern.TestEventArgs>(new FromEventPattern(), "RemoveThrows");
  305. var d = ys.Subscribe(_ => { Assert.True(false); }, ex => exRem = ex, () => { Assert.True(false); });
  306. ReactiveAssert.Throws<InvalidOperationException>(d.Dispose);
  307. }
  308. [TestMethod]
  309. public void FromEventPattern_Reflection_Instance_E1()
  310. {
  311. var scheduler = new TestScheduler();
  312. var fe = new FromEventPattern();
  313. scheduler.ScheduleAbsolute(50, () => fe.M1(1));
  314. scheduler.ScheduleAbsolute(150, () => fe.M1(2));
  315. scheduler.ScheduleAbsolute(250, () => fe.M1(3));
  316. scheduler.ScheduleAbsolute(350, () => fe.M1(4));
  317. scheduler.ScheduleAbsolute(450, () => fe.M1(5));
  318. scheduler.ScheduleAbsolute(1050, () => fe.M1(6));
  319. var results = scheduler.Start(() =>
  320. Observable.FromEventPattern<FromEventPattern.TestEventArgs>(fe, "E1").Select(evt => new { Sender = evt.Sender, EventArgs = (object)evt.EventArgs })
  321. );
  322. results.Messages.AssertEqual(
  323. OnNext(250, new { Sender = (object)fe, EventArgs = (object)new FromEventPattern.TestEventArgs { Id = 3 } }),
  324. OnNext(350, new { Sender = (object)fe, EventArgs = (object)new FromEventPattern.TestEventArgs { Id = 4 } }),
  325. OnNext(450, new { Sender = (object)fe, EventArgs = (object)new FromEventPattern.TestEventArgs { Id = 5 } })
  326. );
  327. }
  328. [TestMethod]
  329. public void FromEventPattern_Reflection_Instance_E2()
  330. {
  331. var scheduler = new TestScheduler();
  332. var fe = new FromEventPattern();
  333. scheduler.ScheduleAbsolute(50, () => fe.M2(1));
  334. scheduler.ScheduleAbsolute(150, () => fe.M2(2));
  335. scheduler.ScheduleAbsolute(250, () => fe.M2(3));
  336. scheduler.ScheduleAbsolute(350, () => fe.M2(4));
  337. scheduler.ScheduleAbsolute(450, () => fe.M2(5));
  338. scheduler.ScheduleAbsolute(1050, () => fe.M2(6));
  339. var results = scheduler.Start(() =>
  340. Observable.FromEventPattern<FromEventPattern.TestEventArgs>(fe, "E2").Select(evt => new { Sender = evt.Sender, EventArgs = (object)evt.EventArgs })
  341. );
  342. results.Messages.AssertEqual(
  343. OnNext(250, new { Sender = (object)fe, EventArgs = (object)new FromEventPattern.TestEventArgs { Id = 3 } }),
  344. OnNext(350, new { Sender = (object)fe, EventArgs = (object)new FromEventPattern.TestEventArgs { Id = 4 } }),
  345. OnNext(450, new { Sender = (object)fe, EventArgs = (object)new FromEventPattern.TestEventArgs { Id = 5 } })
  346. );
  347. }
  348. [TestMethod]
  349. public void FromEventPattern_Reflection_Instance_E2_WithSender()
  350. {
  351. var scheduler = new TestScheduler();
  352. var fe = new FromEventPattern();
  353. scheduler.ScheduleAbsolute(50, () => fe.M2(1));
  354. scheduler.ScheduleAbsolute(150, () => fe.M2(2));
  355. scheduler.ScheduleAbsolute(250, () => fe.M2(3));
  356. scheduler.ScheduleAbsolute(350, () => fe.M2(4));
  357. scheduler.ScheduleAbsolute(450, () => fe.M2(5));
  358. scheduler.ScheduleAbsolute(1050, () => fe.M2(6));
  359. var results = scheduler.Start(() =>
  360. Observable.FromEventPattern<object, FromEventPattern.TestEventArgs>(fe, "E2").Select(evt => new { Sender = evt.Sender, EventArgs = (object)evt.EventArgs })
  361. );
  362. results.Messages.AssertEqual(
  363. OnNext(250, new { Sender = (object)fe, EventArgs = (object)new FromEventPattern.TestEventArgs { Id = 3 } }),
  364. OnNext(350, new { Sender = (object)fe, EventArgs = (object)new FromEventPattern.TestEventArgs { Id = 4 } }),
  365. OnNext(450, new { Sender = (object)fe, EventArgs = (object)new FromEventPattern.TestEventArgs { Id = 5 } })
  366. );
  367. }
  368. [TestMethod]
  369. public void FromEventPattern_Reflection_Instance_E3()
  370. {
  371. var scheduler = new TestScheduler();
  372. var fe = new FromEventPattern();
  373. scheduler.ScheduleAbsolute(50, () => fe.M3(1));
  374. scheduler.ScheduleAbsolute(150, () => fe.M3(2));
  375. scheduler.ScheduleAbsolute(250, () => fe.M3(3));
  376. scheduler.ScheduleAbsolute(350, () => fe.M3(4));
  377. scheduler.ScheduleAbsolute(450, () => fe.M3(5));
  378. scheduler.ScheduleAbsolute(1050, () => fe.M3(6));
  379. var results = scheduler.Start(() =>
  380. Observable.FromEventPattern<FromEventPattern.TestEventArgs>(fe, "E3").Select(evt => new { Sender = evt.Sender, EventArgs = (object)evt.EventArgs })
  381. );
  382. results.Messages.AssertEqual(
  383. OnNext(250, new { Sender = (object)fe, EventArgs = (object)new FromEventPattern.TestEventArgs { Id = 3 } }),
  384. OnNext(350, new { Sender = (object)fe, EventArgs = (object)new FromEventPattern.TestEventArgs { Id = 4 } }),
  385. OnNext(450, new { Sender = (object)fe, EventArgs = (object)new FromEventPattern.TestEventArgs { Id = 5 } })
  386. );
  387. }
  388. #if DESKTOPCLR && NET472
  389. [TestMethod]
  390. public void FromEventPattern_Reflection_Instance_MissingAccessors()
  391. {
  392. var asm = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("EventsTest"), System.Reflection.Emit.AssemblyBuilderAccess.RunAndSave);
  393. var mod = asm.DefineDynamicModule("Events");
  394. var tpe = mod.DefineType("FromEvent");
  395. var ev1 = tpe.DefineEvent("Bar", (EventAttributes)MethodAttributes.Public, typeof(Action));
  396. var add = tpe.DefineMethod("add_Bar", MethodAttributes.Public, CallingConventions.Standard, typeof(void), new Type[0]);
  397. var ge1 = add.GetILGenerator();
  398. ge1.Emit(System.Reflection.Emit.OpCodes.Ret);
  399. ev1.SetAddOnMethod(add);
  400. var ev2 = tpe.DefineEvent("Foo", (EventAttributes)MethodAttributes.Public, typeof(Action));
  401. var rem = tpe.DefineMethod("remove_Foo", MethodAttributes.Public, CallingConventions.Standard, typeof(void), new Type[0]);
  402. var ge2 = rem.GetILGenerator();
  403. ge2.Emit(System.Reflection.Emit.OpCodes.Ret);
  404. ev2.SetRemoveOnMethod(rem);
  405. var evt = tpe.DefineEvent("Evt", (EventAttributes)MethodAttributes.Public, typeof(Action));
  406. evt.SetAddOnMethod(add);
  407. evt.SetRemoveOnMethod(rem);
  408. var res = tpe.CreateType();
  409. var obj = Activator.CreateInstance(res);
  410. ReactiveAssert.Throws<InvalidOperationException>(() => Observable.FromEventPattern<EventArgs>(obj, "Bar"));
  411. ReactiveAssert.Throws<InvalidOperationException>(() => Observable.FromEventPattern<EventArgs>(obj, "Foo"));
  412. ReactiveAssert.Throws<InvalidOperationException>(() => Observable.FromEventPattern<EventArgs>(obj, "Evt"));
  413. }
  414. #endif
  415. #endregion
  416. #region Static events
  417. [TestMethod]
  418. public void FromEventPattern_Reflection_Static_ArgumentChecking()
  419. {
  420. ReactiveAssert.Throws</**/ArgumentNullException>(() => Observable.FromEventPattern(default, "foo"));
  421. ReactiveAssert.Throws</**/ArgumentNullException>(() => Observable.FromEventPattern(typeof(FromEventPattern_ArgCheck), null));
  422. ReactiveAssert.Throws</**/ArgumentNullException>(() => Observable.FromEventPattern(default, "foo", Scheduler.Default));
  423. ReactiveAssert.Throws</**/ArgumentNullException>(() => Observable.FromEventPattern(typeof(FromEventPattern_ArgCheck), null, Scheduler.Default));
  424. ReactiveAssert.Throws</**/ArgumentNullException>(() => Observable.FromEventPattern(typeof(FromEventPattern_ArgCheck), "foo", default));
  425. ReactiveAssert.Throws<InvalidOperationException>(() => Observable.FromEventPattern(typeof(FromEventPattern_ArgCheck), "foo"));
  426. ReactiveAssert.Throws</**/ArgumentNullException>(() => Observable.FromEventPattern<EventArgs>(default, "foo"));
  427. ReactiveAssert.Throws</**/ArgumentNullException>(() => Observable.FromEventPattern<EventArgs>(typeof(FromEventPattern_ArgCheck), null));
  428. ReactiveAssert.Throws</**/ArgumentNullException>(() => Observable.FromEventPattern<EventArgs>(default, "foo", Scheduler.Default));
  429. ReactiveAssert.Throws</**/ArgumentNullException>(() => Observable.FromEventPattern<EventArgs>(typeof(FromEventPattern_ArgCheck), null, Scheduler.Default));
  430. ReactiveAssert.Throws</**/ArgumentNullException>(() => Observable.FromEventPattern<EventArgs>(typeof(FromEventPattern_ArgCheck), "foo", default));
  431. ReactiveAssert.Throws<InvalidOperationException>(() => Observable.FromEventPattern<EventArgs>(typeof(FromEventPattern_ArgCheck), "foo"));
  432. ReactiveAssert.Throws</**/ArgumentNullException>(() => Observable.FromEventPattern<object, EventArgs>(default, "foo"));
  433. ReactiveAssert.Throws</**/ArgumentNullException>(() => Observable.FromEventPattern<object, EventArgs>(typeof(FromEventPattern_ArgCheck), null));
  434. ReactiveAssert.Throws</**/ArgumentNullException>(() => Observable.FromEventPattern<object, EventArgs>(default, "foo", Scheduler.Default));
  435. ReactiveAssert.Throws</**/ArgumentNullException>(() => Observable.FromEventPattern<object, EventArgs>(typeof(FromEventPattern_ArgCheck), null, Scheduler.Default));
  436. ReactiveAssert.Throws</**/ArgumentNullException>(() => Observable.FromEventPattern<object, EventArgs>(typeof(FromEventPattern_ArgCheck), "foo", default));
  437. ReactiveAssert.Throws<InvalidOperationException>(() => Observable.FromEventPattern<object, EventArgs>(typeof(FromEventPattern_ArgCheck), "foo"));
  438. }
  439. [TestMethod]
  440. public void FromEventPattern_Reflection_Static_E6()
  441. {
  442. var scheduler = new TestScheduler();
  443. scheduler.ScheduleAbsolute(50, () => FromEventPattern.M6(1));
  444. scheduler.ScheduleAbsolute(150, () => FromEventPattern.M6(2));
  445. scheduler.ScheduleAbsolute(250, () => FromEventPattern.M6(3));
  446. scheduler.ScheduleAbsolute(350, () => FromEventPattern.M6(4));
  447. scheduler.ScheduleAbsolute(450, () => FromEventPattern.M6(5));
  448. scheduler.ScheduleAbsolute(1050, () => FromEventPattern.M6(6));
  449. var results = scheduler.Start(() =>
  450. Observable.FromEventPattern<FromEventPattern.TestEventArgs>(typeof(FromEventPattern), "E6").Select(evt => new { Sender = evt.Sender, EventArgs = (object)evt.EventArgs })
  451. );
  452. results.Messages.AssertEqual(
  453. OnNext(250, new { Sender = default(object), EventArgs = (object)new FromEventPattern.TestEventArgs { Id = 3 } }),
  454. OnNext(350, new { Sender = default(object), EventArgs = (object)new FromEventPattern.TestEventArgs { Id = 4 } }),
  455. OnNext(450, new { Sender = default(object), EventArgs = (object)new FromEventPattern.TestEventArgs { Id = 5 } })
  456. );
  457. }
  458. [TestMethod]
  459. public void FromEventPattern_Reflection_Static_E6_WithSender()
  460. {
  461. var scheduler = new TestScheduler();
  462. scheduler.ScheduleAbsolute(50, () => FromEventPattern.M6(1));
  463. scheduler.ScheduleAbsolute(150, () => FromEventPattern.M6(2));
  464. scheduler.ScheduleAbsolute(250, () => FromEventPattern.M6(3));
  465. scheduler.ScheduleAbsolute(350, () => FromEventPattern.M6(4));
  466. scheduler.ScheduleAbsolute(450, () => FromEventPattern.M6(5));
  467. scheduler.ScheduleAbsolute(1050, () => FromEventPattern.M6(6));
  468. var results = scheduler.Start(() =>
  469. Observable.FromEventPattern<object, FromEventPattern.TestEventArgs>(typeof(FromEventPattern), "E6").Select(evt => new { Sender = evt.Sender, EventArgs = (object)evt.EventArgs })
  470. );
  471. results.Messages.AssertEqual(
  472. OnNext(250, new { Sender = default(object), EventArgs = (object)new FromEventPattern.TestEventArgs { Id = 3 } }),
  473. OnNext(350, new { Sender = default(object), EventArgs = (object)new FromEventPattern.TestEventArgs { Id = 4 } }),
  474. OnNext(450, new { Sender = default(object), EventArgs = (object)new FromEventPattern.TestEventArgs { Id = 5 } })
  475. );
  476. }
  477. [TestMethod]
  478. public void FromEventPattern_Reflection_Static_NonGeneric_E6()
  479. {
  480. var scheduler = new TestScheduler();
  481. scheduler.ScheduleAbsolute(50, () => FromEventPattern.M6(1));
  482. scheduler.ScheduleAbsolute(150, () => FromEventPattern.M6(2));
  483. scheduler.ScheduleAbsolute(250, () => FromEventPattern.M6(3));
  484. scheduler.ScheduleAbsolute(350, () => FromEventPattern.M6(4));
  485. scheduler.ScheduleAbsolute(450, () => FromEventPattern.M6(5));
  486. scheduler.ScheduleAbsolute(1050, () => FromEventPattern.M6(6));
  487. var results = scheduler.Start(() =>
  488. Observable.FromEventPattern(typeof(FromEventPattern), "E6").Select(evt => new { Sender = evt.Sender, EventArgs = evt.EventArgs })
  489. );
  490. results.Messages.AssertEqual(
  491. OnNext(250, new { Sender = default(object), EventArgs = (object)new FromEventPattern.TestEventArgs { Id = 3 } }),
  492. OnNext(350, new { Sender = default(object), EventArgs = (object)new FromEventPattern.TestEventArgs { Id = 4 } }),
  493. OnNext(450, new { Sender = default(object), EventArgs = (object)new FromEventPattern.TestEventArgs { Id = 5 } })
  494. );
  495. }
  496. #endregion
  497. #endregion
  498. #region Rx v2.0 behavior
  499. [TestMethod]
  500. public void FromEventPattern_Scheduler1()
  501. {
  502. RunWithScheduler((s, add, remove) => Observable.FromEventPattern<MyEventArgs>(h => { add(); }, h => { remove(); }, s));
  503. }
  504. [TestMethod]
  505. public void FromEventPattern_Scheduler2()
  506. {
  507. RunWithScheduler((s, add, remove) =>
  508. {
  509. MyEventObject.Add = add;
  510. MyEventObject.Remove = remove;
  511. return Observable.FromEventPattern<MyEventArgs>(typeof(MyEventObject), "S", s);
  512. });
  513. }
  514. [TestMethod]
  515. public void FromEventPattern_Scheduler3()
  516. {
  517. RunWithScheduler((s, add, remove) =>
  518. {
  519. MyEventObject.Add = add;
  520. MyEventObject.Remove = remove;
  521. return Observable.FromEventPattern<MyEventArgs>(new MyEventObject(), "I", s);
  522. });
  523. }
  524. [TestMethod]
  525. public void FromEventPattern_Scheduler4()
  526. {
  527. RunWithScheduler((s, add, remove) => Observable.FromEventPattern(h => { add(); }, h => { remove(); }, s));
  528. }
  529. [TestMethod]
  530. public void FromEventPattern_Scheduler5()
  531. {
  532. RunWithScheduler((s, add, remove) =>
  533. {
  534. MyEventObject.Add = add;
  535. MyEventObject.Remove = remove;
  536. return Observable.FromEventPattern(typeof(MyEventObject), "S", s);
  537. });
  538. }
  539. [TestMethod]
  540. public void FromEventPattern_Scheduler6()
  541. {
  542. RunWithScheduler((s, add, remove) =>
  543. {
  544. MyEventObject.Add = add;
  545. MyEventObject.Remove = remove;
  546. return Observable.FromEventPattern(new MyEventObject(), "I", s);
  547. });
  548. }
  549. [TestMethod]
  550. public void FromEventPattern_Scheduler7()
  551. {
  552. RunWithScheduler((s, add, remove) => Observable.FromEventPattern<EventHandler<MyEventArgs>, MyEventArgs>(h => { add(); }, h => { remove(); }, s));
  553. }
  554. [TestMethod]
  555. public void FromEventPattern_Scheduler8()
  556. {
  557. RunWithScheduler((s, add, remove) => Observable.FromEventPattern<EventHandler<MyEventArgs>, MyEventArgs>(h => h, h => { add(); }, h => { remove(); }, s));
  558. }
  559. [TestMethod]
  560. public void FromEventPattern_Scheduler9()
  561. {
  562. RunWithScheduler((s, add, remove) =>
  563. {
  564. MyEventObject.Add = add;
  565. MyEventObject.Remove = remove;
  566. return Observable.FromEventPattern<object, MyEventArgs>(typeof(MyEventObject), "S", s);
  567. });
  568. }
  569. [TestMethod]
  570. public void FromEventPattern_Scheduler10()
  571. {
  572. RunWithScheduler((s, add, remove) =>
  573. {
  574. MyEventObject.Add = add;
  575. MyEventObject.Remove = remove;
  576. return Observable.FromEventPattern<object, MyEventArgs>(new MyEventObject(), "I", s);
  577. });
  578. }
  579. [TestMethod]
  580. public void FromEventPattern_Scheduler11()
  581. {
  582. RunWithScheduler((s, add, remove) => Observable.FromEventPattern<EventHandler<MyEventArgs>, object, MyEventArgs>(h => { add(); }, h => { remove(); }, s));
  583. }
  584. private void RunWithScheduler<T>(Func<IScheduler, Action, Action, IObservable<T>> run)
  585. {
  586. var n = 0;
  587. var a = 0;
  588. var r = 0;
  589. var s = new MyEventScheduler(() => n++);
  590. var add = new Action(() => a++);
  591. var rem = new Action(() => r++);
  592. var xs = run(s, add, rem);
  593. Assert.Equal(0, n);
  594. Assert.Equal(0, a);
  595. Assert.Equal(0, r);
  596. var d1 = xs.Subscribe();
  597. Assert.Equal(1, n);
  598. Assert.Equal(1, a);
  599. Assert.Equal(0, r);
  600. var d2 = xs.Subscribe();
  601. Assert.Equal(1, n);
  602. Assert.Equal(1, a);
  603. Assert.Equal(0, r);
  604. d1.Dispose();
  605. Assert.Equal(1, n);
  606. Assert.Equal(1, a);
  607. Assert.Equal(0, r);
  608. d2.Dispose();
  609. Assert.Equal(2, n);
  610. Assert.Equal(1, a);
  611. Assert.Equal(1, r);
  612. }
  613. #endregion
  614. }
  615. public class FromEventPattern
  616. {
  617. [DebuggerDisplay("{Id}")]
  618. public class TestEventArgs : EventArgs, IEquatable<TestEventArgs>
  619. {
  620. public int Id { get; set; }
  621. public override string ToString()
  622. {
  623. return Id.ToString();
  624. }
  625. public bool Equals(TestEventArgs other)
  626. {
  627. if (other == this)
  628. {
  629. return true;
  630. }
  631. if (other == null)
  632. {
  633. return false;
  634. }
  635. return other.Id == Id;
  636. }
  637. public override bool Equals(object obj)
  638. {
  639. return Equals(obj as TestEventArgs);
  640. }
  641. public override int GetHashCode()
  642. {
  643. return Id;
  644. }
  645. }
  646. public delegate void TestEventHandler(object sender, TestEventArgs eventArgs);
  647. public event TestEventHandler E1;
  648. public void M1(int i)
  649. {
  650. E1?.Invoke(this, new TestEventArgs { Id = i });
  651. }
  652. public event EventHandler<TestEventArgs> E2;
  653. public void M2(int i)
  654. {
  655. E2?.Invoke(this, new TestEventArgs { Id = i });
  656. }
  657. public event Action<object, TestEventArgs> E3;
  658. public void M3(int i)
  659. {
  660. E3?.Invoke(this, new TestEventArgs { Id = i });
  661. }
  662. public event Action<int> E4;
  663. public void M4(int i)
  664. {
  665. E4?.Invoke(i);
  666. }
  667. public event TestEventHandler AddThrows
  668. {
  669. add { throw new InvalidOperationException(); }
  670. remove { }
  671. }
  672. public event TestEventHandler RemoveThrows
  673. {
  674. add { }
  675. remove { throw new InvalidOperationException(); }
  676. }
  677. public event EventHandler E5;
  678. public void M5(int i)
  679. {
  680. E5?.Invoke(this, new TestEventArgs { Id = i });
  681. }
  682. public static event EventHandler<TestEventArgs> E6;
  683. public static void M6(int i)
  684. {
  685. E6?.Invoke(null, new TestEventArgs { Id = i });
  686. }
  687. }
  688. public delegate void MyAction(int x);
  689. public class FromEvent
  690. {
  691. public event Action A;
  692. public void OnA()
  693. {
  694. A?.Invoke();
  695. }
  696. public event Action<int> B;
  697. public void OnB(int x)
  698. {
  699. B?.Invoke(x);
  700. }
  701. public event MyAction C;
  702. public void OnC(int x)
  703. {
  704. C?.Invoke(x);
  705. }
  706. }
  707. internal class FromEventPattern_ArgCheck
  708. {
  709. #pragma warning disable 67
  710. public event Action E1;
  711. public event Action<int, int> E2;
  712. public event Action<object, object> E3;
  713. public event Action<object, int> E4;
  714. public event Func<object, EventArgs, int> E5;
  715. public event Action<EventArgs> E6;
  716. #pragma warning restore 67
  717. }
  718. public class FromEventPattern_VarianceCheck
  719. {
  720. #pragma warning disable 67
  721. public event EventHandler<EventArgs> E1;
  722. public event EventHandler<CancelEventArgs> E2;
  723. public event Action<string, EventArgs> E3;
  724. #pragma warning restore 67
  725. public void OnE2(CancelEventArgs args)
  726. {
  727. E2?.Invoke(this, args);
  728. }
  729. public void OnE3(string sender)
  730. {
  731. E3?.Invoke(sender, EventArgs.Empty);
  732. }
  733. }
  734. internal class MyEventObject
  735. {
  736. public static Action Add;
  737. public static Action Remove;
  738. public event EventHandler<MyEventArgs> I
  739. {
  740. add { Add(); }
  741. remove { Remove(); }
  742. }
  743. public static event EventHandler<MyEventArgs> S
  744. {
  745. add { Add(); }
  746. remove { Remove(); }
  747. }
  748. }
  749. internal class MyEventSource
  750. {
  751. public event EventHandler<MyEventArgs> Bar;
  752. public void OnBar(int value)
  753. {
  754. Bar?.Invoke(this, new MyEventArgs(value));
  755. }
  756. }
  757. internal class MyEventArgs : EventArgs
  758. {
  759. public MyEventArgs(int value)
  760. {
  761. Value = value;
  762. }
  763. public int Value { get; private set; }
  764. }
  765. internal class MyEventSyncCtx : SynchronizationContext
  766. {
  767. public int PostCount { get; private set; }
  768. public override void Post(SendOrPostCallback d, object state)
  769. {
  770. var old = Current;
  771. SetSynchronizationContext(this);
  772. try
  773. {
  774. PostCount++;
  775. d(state);
  776. }
  777. finally
  778. {
  779. SetSynchronizationContext(old);
  780. }
  781. }
  782. }
  783. internal class MyEventScheduler : LocalScheduler
  784. {
  785. private readonly Action _schedule;
  786. public MyEventScheduler(Action schedule)
  787. {
  788. _schedule = schedule;
  789. }
  790. public override IDisposable Schedule<TState>(TState state, Func<IScheduler, TState, IDisposable> action)
  791. {
  792. _schedule();
  793. return action(this, state);
  794. }
  795. public override IDisposable Schedule<TState>(TState state, TimeSpan dueTime, Func<IScheduler, TState, IDisposable> action)
  796. {
  797. throw new NotImplementedException();
  798. }
  799. }
  800. }