PageRenderTime 54ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Castle.Facilities.Synchronize/Result.Void.cs

http://github.com/castleproject/Castle.Windsor-READONLY
C# | 443 lines | 210 code | 43 blank | 190 comment | 17 complexity | e09e62d31837f72a00f34a2f1245d3d3 MD5 | raw file
  1. // Copyright 2004-2011 Castle Project - http://www.castleproject.org/
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. namespace Castle.Facilities.Synchronize
  15. {
  16. using System;
  17. /// <summary>
  18. /// Delegate called when results are available.
  19. /// </summary>
  20. /// <param name = "result">The result.</param>
  21. public delegate void ResultDelegate(Result result);
  22. /// <summary>
  23. /// Delegate called when typed results are available.
  24. /// </summary>
  25. /// <typeparam name = "T">The result type.</typeparam>
  26. /// <param name = "result">The result.</param>
  27. public delegate void ResultDelegate<T>(Result<T> result);
  28. /// <summary>
  29. /// Represents the result of an asynchronous operation.
  30. /// </summary>
  31. public class Result : AbstractAsyncResult
  32. {
  33. [ThreadStatic]
  34. internal static Result Last;
  35. private readonly object guard = new object();
  36. private AsyncCallback asyncCallback;
  37. /// <summary>
  38. /// Initializes the <see cref = "Result" />.
  39. /// </summary>
  40. internal Result()
  41. : base(CallCallback, null)
  42. {
  43. }
  44. /// <summary>
  45. /// Gets the output values.
  46. /// </summary>
  47. public object[] OutValues { get; private set; }
  48. /// <summary>
  49. /// Gets the unbound output values.
  50. /// </summary>
  51. public object[] UnboundOutValues { get; private set; }
  52. /// <summary>
  53. /// Waits for the result to complete.
  54. /// </summary>
  55. public void End()
  56. {
  57. End(this);
  58. }
  59. /// <summary>
  60. /// Waits for the result to complete with output.
  61. /// </summary>
  62. /// <typeparam name = "TOut1">The output type.</typeparam>
  63. /// <param name = "out1">The output value.</param>
  64. public void End<TOut1>(out TOut1 out1)
  65. {
  66. End();
  67. out1 = (TOut1)ExtractOutOfType(typeof(TOut1), 0);
  68. CreateUnboundOutValues(1);
  69. }
  70. /// <summary>
  71. /// Waits for the result to complete with outputs.
  72. /// </summary>
  73. /// <typeparam name = "TOut1">The first output type.</typeparam>
  74. /// <typeparam name = "TOut2">The first output type.</typeparam>
  75. /// <param name = "out1">The first output type.</param>
  76. /// <param name = "out2">The second output value.</param>
  77. public void End<TOut1, TOut2>(out TOut1 out1, out TOut2 out2)
  78. {
  79. End();
  80. out1 = (TOut1)ExtractOutOfType(typeof(TOut1), 0);
  81. out2 = (TOut2)ExtractOutOfType(typeof(TOut2), 1);
  82. CreateUnboundOutValues(2);
  83. }
  84. /// <summary>
  85. /// Waits for the result to complete with outputs.
  86. /// </summary>
  87. /// <typeparam name = "TOut1">The first output type.</typeparam>
  88. /// <typeparam name = "TOut2">The second output type.</typeparam>
  89. /// <typeparam name = "TOut3">The third output type.</typeparam>
  90. /// <param name = "out1">The first output type.</param>
  91. /// <param name = "out2">The second output type.</param>
  92. /// <param name = "out3">The third output type.</param>
  93. public void End<TOut1, TOut2, TOut3>(out TOut1 out1, out TOut2 out2, out TOut3 out3)
  94. {
  95. End();
  96. out1 = (TOut1)ExtractOutOfType(typeof(TOut1), 0);
  97. out2 = (TOut2)ExtractOutOfType(typeof(TOut2), 1);
  98. out3 = (TOut3)ExtractOutOfType(typeof(TOut3), 2);
  99. CreateUnboundOutValues(3);
  100. }
  101. /// <summary>
  102. /// Waits for the result to complete with outputs.
  103. /// </summary>
  104. /// <typeparam name = "TOut1">The first output type.</typeparam>
  105. /// <typeparam name = "TOut2">The second output type.</typeparam>
  106. /// <typeparam name = "TOut3">The third output type.</typeparam>
  107. /// <typeparam name = "TOut4">The fourth output type.</typeparam>
  108. /// <param name = "out1">The first output type.</param>
  109. /// <param name = "out2">The second output type.</param>
  110. /// <param name = "out3">The third output type.</param>
  111. /// <param name = "out4">The fourth output value</param>
  112. public void End<TOut1, TOut2, TOut3, TOut4>(out TOut1 out1, out TOut2 out2, out TOut3 out3, out TOut4 out4)
  113. {
  114. End();
  115. out1 = (TOut1)ExtractOutOfType(typeof(TOut1), 0);
  116. out2 = (TOut2)ExtractOutOfType(typeof(TOut2), 1);
  117. out3 = (TOut3)ExtractOutOfType(typeof(TOut3), 2);
  118. out4 = (TOut4)ExtractOutOfType(typeof(TOut4), 3);
  119. CreateUnboundOutValues(4);
  120. }
  121. /// <summary>
  122. /// Waits for the result to complete with outputs.
  123. /// </summary>
  124. /// <typeparam name = "TOut1">The first output type.</typeparam>
  125. /// <typeparam name = "TOut2">The second output type.</typeparam>
  126. /// <typeparam name = "TOut3">The third output type.</typeparam>
  127. /// <typeparam name = "TOut4">The fourth output type.</typeparam>
  128. /// <param name = "result">The asynchronous result.</param>
  129. /// <param name = "out1">The first output type.</param>
  130. /// <param name = "out2">The second output type.</param>
  131. /// <param name = "out3">The third output type.</param>
  132. /// <param name = "out4">The fourth output value</param>
  133. public void End<TOut1, TOut2, TOut3, TOut4>(IAsyncResult result, out TOut1 out1, out TOut2 out2,
  134. out TOut3 out3, out TOut4 out4)
  135. {
  136. EnsureResult(result).End(out out1, out out2, out out3, out out4);
  137. }
  138. /// <summary>
  139. /// Gets the output argument at index <paramref name = "index" />.
  140. /// </summary>
  141. /// <typeparam name = "TOut">The output type..</typeparam>
  142. /// <param name = "index">The output index.</param>
  143. /// <returns>The output value.</returns>
  144. public TOut GetOutArg<TOut>(int index)
  145. {
  146. return (TOut)ExtractOutOfType(typeof(TOut), index);
  147. }
  148. /// <summary>
  149. /// Gets the unbound output argument at index <paramref name = "index" />.
  150. /// </summary>
  151. /// <typeparam name = "TOut">The output type.</typeparam>
  152. /// <param name = "index">The output index.</param>
  153. /// <returns>The output value.</returns>
  154. public TOut GetUnboundOutArg<TOut>(int index)
  155. {
  156. return (TOut)ExtractUnboundOutOfType(typeof(TOut), index);
  157. }
  158. /// <summary>
  159. /// Creates the unbound output values starting at <paramref name = "fromIndex" />.
  160. /// </summary>
  161. /// <param name = "fromIndex">The starting index.</param>
  162. protected internal void CreateUnboundOutValues(int fromIndex)
  163. {
  164. UnboundOutValues = new object[Math.Max(0, OutValues.Length - fromIndex)];
  165. if (UnboundOutValues.Length > 0)
  166. {
  167. Array.Copy(OutValues, fromIndex, UnboundOutValues, 0, UnboundOutValues.Length);
  168. }
  169. }
  170. /// <summary>
  171. /// Extracts the output at index <paramref name = "index" />
  172. /// </summary>
  173. /// <param name = "type">The expected type.</param>
  174. /// <param name = "index">The output index.</param>
  175. /// <returns>The extracted output.</returns>
  176. protected internal object ExtractOutOfType(Type type, int index)
  177. {
  178. return ExtractOutOfType(type, index, OutValues);
  179. }
  180. /// <summary>
  181. /// Extracts the unbound output at index <paramref name = "index" />
  182. /// </summary>
  183. /// <param name = "type">The expected type.</param>
  184. /// <param name = "index">The output index.</param>
  185. /// <returns>The extracted outout.</returns>
  186. protected internal object ExtractUnboundOutOfType(Type type, int index)
  187. {
  188. return ExtractOutOfType(type, index, UnboundOutValues);
  189. }
  190. /// <summary>
  191. /// Set the asynchronous callback information.
  192. /// </summary>
  193. /// <param name = "callback">The callback.</param>
  194. /// <param name = "state">The async state.</param>
  195. internal void SetCallbackInfo(AsyncCallback callback, object state)
  196. {
  197. if (callback != null)
  198. {
  199. lock (guard)
  200. {
  201. AsyncState = state;
  202. asyncCallback = callback;
  203. if (IsCompleted)
  204. {
  205. asyncCallback(this);
  206. }
  207. }
  208. }
  209. }
  210. /// <summary>
  211. /// Completes the asynchronous request with exception.
  212. /// </summary>
  213. /// <param name = "synchronously">true if synchronously.</param>
  214. /// <param name = "exception">The exception.</param>
  215. internal void SetException(bool synchronously, Exception exception)
  216. {
  217. lock (guard)
  218. {
  219. Complete(synchronously, exception);
  220. }
  221. }
  222. /// <summary>
  223. /// Completes the asynchronous request.
  224. /// </summary>
  225. /// <param name = "synchronously">true if synchronously.</param>
  226. /// <param name = "result">The result.</param>
  227. /// <param name = "outs">The additional outputs.</param>
  228. internal void SetValues(bool synchronously, object result, object[] outs)
  229. {
  230. lock (guard)
  231. {
  232. OutValues = outs;
  233. Complete(synchronously, result);
  234. }
  235. }
  236. private object ExtractOutOfType(Type type, int index, object[] outs)
  237. {
  238. if (outs == null)
  239. {
  240. throw new InvalidOperationException("Out arguments are not available. Did you forget to call End?");
  241. }
  242. if (index >= outs.Length)
  243. {
  244. throw new IndexOutOfRangeException(string.Format(
  245. "There is no out argument at index {0}. Please check the method signature.", index));
  246. }
  247. var outArg = outs[index];
  248. if (outArg == null && type.IsValueType)
  249. {
  250. throw new InvalidOperationException(string.Format(
  251. "The out argument at index {0} is a value type and cannot be null. Please check the method signature.", index));
  252. }
  253. if (!type.IsInstanceOfType(outArg))
  254. {
  255. throw new InvalidOperationException(string.Format(
  256. "There is a type mismatch for the out argument at index {0}. Expected {1}, but found {2}. Please check the method signature.",
  257. index, type.FullName, outArg.GetType().FullName));
  258. }
  259. return outArg;
  260. }
  261. /// <summary>
  262. /// Waits for the result to complete with outputs.
  263. /// </summary>
  264. /// <typeparam name = "TOut1">The output type.</typeparam>
  265. /// <param name = "result">The asynchronous result.</param>
  266. /// <param name = "out1">The output value.</param>
  267. public static void End<TOut1>(IAsyncResult result, out TOut1 out1)
  268. {
  269. EnsureResult(result).End(out out1);
  270. }
  271. /// <summary>
  272. /// Waits for the result to complete with outputs.
  273. /// </summary>
  274. /// <typeparam name = "TOut1">The first output type.</typeparam>
  275. /// <typeparam name = "TOut2">The first output type.</typeparam>
  276. /// <param name = "result">The asynchronous result.</param>
  277. /// <param name = "out1">The first output type.</param>
  278. /// <param name = "out2">The second output value.</param>
  279. public static void End<TOut1, TOut2>(IAsyncResult result, out TOut1 out1, out TOut2 out2)
  280. {
  281. EnsureResult(result).End(out out1, out out2);
  282. }
  283. /// <summary>
  284. /// Waits for the result to complete with outputs.
  285. /// </summary>
  286. /// <typeparam name = "TOut1">The first output type.</typeparam>
  287. /// <typeparam name = "TOut2">The second output type.</typeparam>
  288. /// <typeparam name = "TOut3">The third output type.</typeparam>
  289. /// <param name = "result">The asynchronous result.</param>
  290. /// <param name = "out1">The first output type.</param>
  291. /// <param name = "out2">The second output type.</param>
  292. /// <param name = "out3">The third output type.</param>
  293. public static void End<TOut1, TOut2, TOut3>(IAsyncResult result, out TOut1 out1, out TOut2 out2, out TOut3 out3)
  294. {
  295. EnsureResult(result).End(out out1, out out2, out out3);
  296. }
  297. /// <summary>
  298. /// Gets the result of the last called made.
  299. /// </summary>
  300. /// <param name = "action">The action to execute.</param>
  301. /// <returns>The result handle.</returns>
  302. public static Result Of(Action action)
  303. {
  304. action();
  305. return ResetLastResult();
  306. }
  307. /// <summary>
  308. /// Gets the result of the last called made.
  309. /// </summary>
  310. /// <param name = "action">The action to execute.</param>
  311. /// <param name = "callback">The callback.</param>
  312. /// <param name = "state">The async state.</param>
  313. /// <returns>The result handle.</returns>
  314. public static Result Of(Action action, AsyncCallback callback, object state)
  315. {
  316. var result = Of(action);
  317. result.SetCallbackInfo(callback, state);
  318. return result;
  319. }
  320. /// <summary>
  321. /// Gets the result of the last called made.
  322. /// </summary>
  323. /// <param name = "action">The action to execute.</param>
  324. /// <param name = "callback">The callback.</param>
  325. /// <param name = "state">The async state.</param>
  326. /// <returns>The result handle.</returns>
  327. public static Result Of(Action action, ResultDelegate callback, object state)
  328. {
  329. var result = Of(action);
  330. result.SetCallbackInfo((IAsyncResult cb) => callback(result), state);
  331. return result;
  332. }
  333. /// <summary>
  334. /// Gets the result of the last called made.
  335. /// </summary>
  336. /// <typeparam name = "T">The result type.</typeparam>
  337. /// <param name = "ignored"></param>
  338. /// <returns>The result handle.</returns>
  339. public static Result<T> Of<T>(T ignored)
  340. {
  341. return new Result<T>(ResetLastResult());
  342. }
  343. /// <summary>
  344. /// Gets the result of the last called made.
  345. /// </summary>
  346. /// <typeparam name = "T">The result type.</typeparam>
  347. /// <param name = "ignored"></param>
  348. /// <param name = "callback">The callback.</param>
  349. /// <param name = "state">The async state.</param>
  350. /// <returns>The result handle.</returns>
  351. public static Result<T> Of<T>(T ignored, AsyncCallback callback, object state)
  352. {
  353. var result = Of(ignored);
  354. result.SetCallbackInfo(callback, state);
  355. return result;
  356. }
  357. /// <summary>
  358. /// Gets the result of the last called made.
  359. /// </summary>
  360. /// <typeparam name = "T">The result type.</typeparam>
  361. /// <param name = "ignored"></param>
  362. /// <param name = "callback">The callback.</param>
  363. /// <param name = "state">The async state.</param>
  364. /// <returns>The result handle.</returns>
  365. public static Result<T> Of<T>(T ignored, ResultDelegate<T> callback, object state)
  366. {
  367. var result = Of(ignored);
  368. result.SetCallbackInfo((IAsyncResult cb) => callback(result), state);
  369. return result;
  370. }
  371. internal static Result EnsureResult(IAsyncResult asyncResult)
  372. {
  373. var result = asyncResult as Result;
  374. if (result == null)
  375. {
  376. throw new InvalidOperationException("Unrecoginized IAsyncResult, was this from a call to Result.Of()?");
  377. }
  378. return result;
  379. }
  380. private static void CallCallback(IAsyncResult asyncResult)
  381. {
  382. var result = (Result)asyncResult;
  383. if (result.asyncCallback != null)
  384. {
  385. result.asyncCallback(asyncResult);
  386. }
  387. }
  388. private static Result ResetLastResult()
  389. {
  390. var last = Last;
  391. if (last == null)
  392. {
  393. throw new InvalidOperationException(
  394. "The result is only available for synchronized methods.");
  395. }
  396. Last = null;
  397. return last;
  398. }
  399. }
  400. }