Mercurial > pub > ImplabNet
comparison Implab/AbstractPromise.cs @ 243:b1e0ffdf3451 v3
working on promises
author | cin |
---|---|
date | Wed, 24 Jan 2018 19:24:10 +0300 |
parents | cbe10ac0731e |
children | eee3e49dd1ff |
comparison
equal
deleted
inserted
replaced
242:cbe10ac0731e | 243:b1e0ffdf3451 |
---|---|
1 using System; | 1 using System; |
2 using System.Diagnostics; | |
3 using System.Reflection; | |
2 using Implab.Parallels; | 4 using Implab.Parallels; |
3 | 5 |
4 namespace Implab { | 6 namespace Implab { |
5 public abstract class AbstractPromise : AbstractEvent<AbstractPromise.HandlerDescriptor>, IPromise { | 7 public abstract class AbstractPromise : AbstractEvent<AbstractPromise.HandlerDescriptor>, IPromise { |
6 public class HandlerDescriptor { | 8 public class HandlerDescriptor { |
7 readonly Action m_handler; | 9 readonly Action m_resolve; |
8 readonly Action<Exception> m_error; | 10 readonly Action<Exception> m_reject; |
11 | |
12 readonly IDeferred m_deferred; | |
9 public HandlerDescriptor(Action success, Action<Exception> error) { | 13 public HandlerDescriptor(Action success, Action<Exception> error) { |
10 m_handler = success; | 14 m_resolve = success; |
11 m_error = error; | 15 m_reject = error; |
12 } | 16 } |
13 | 17 |
14 public void SignalSuccess() { | 18 public void SignalSuccess() { |
15 if (m_handler != null) { | 19 try { |
16 try { | 20 if (m_resolve != null) |
17 m_handler(); | 21 m_resolve(); |
18 // Analysis disable once EmptyGeneralCatchClause | 22 m_deferred.Resolve(); |
19 } catch { | 23 } catch (Exception ex) { |
20 } | 24 m_deferred.Reject(ex); |
21 } | 25 } |
22 } | 26 } |
23 | 27 |
24 public void SignalError(Exception err) { | 28 public void SignalError(Exception err) { |
25 if (m_error != null) { | 29 if (m_reject != null) { |
26 try { | 30 try { |
27 m_error(err); | 31 m_reject(err); |
28 // Analysis disable once EmptyGeneralCatchClause | 32 m_deferred.Resolve(); |
29 } catch { | 33 } catch (Exception ex) { |
34 m_deferred.Reject(ex); | |
30 } | 35 } |
31 } | 36 } |
37 } | |
38 } | |
39 | |
40 PromiseState m_state; | |
41 | |
42 Exception m_error; | |
43 | |
44 public bool IsRejected { | |
45 get { | |
46 return m_state == PromiseState.Rejected; | |
47 } | |
48 } | |
49 | |
50 public bool IsResolved { | |
51 get { | |
52 return m_state == PromiseState.Resolved; | |
53 } | |
54 } | |
55 | |
56 public Exception RejectReason { | |
57 get { | |
58 return m_error; | |
32 } | 59 } |
33 } | 60 } |
34 | 61 |
35 | 62 |
36 #region implemented abstract members of AbstractPromise | 63 #region implemented abstract members of AbstractPromise |
37 | 64 |
38 protected override void SignalHandler(HandlerDescriptor handler, int signal) { | 65 protected override void SignalHandler(HandlerDescriptor handler) { |
39 switch (signal) { | 66 switch (m_state) { |
40 case SUCCEEDED_STATE: | 67 case PromiseState.Resolved: |
41 handler.SignalSuccess(); | 68 handler.SignalSuccess(); |
42 break; | 69 break; |
43 case REJECTED_STATE: | 70 case PromiseState.Rejected: |
44 handler.SignalError(RejectReason); | 71 handler.SignalError(RejectReason); |
45 break; | 72 break; |
46 default: | 73 default: |
47 throw new InvalidOperationException(String.Format("Invalid promise signal: {0}", signal)); | 74 throw new InvalidOperationException(String.Format("Invalid promise signal: {0}", m_state)); |
48 } | 75 } |
49 } | 76 } |
50 | 77 |
51 protected override Signal GetFulfillSignal() { | 78 protected override Signal GetFulfillSignal() { |
52 var signal = new Signal(); | 79 var signal = new Signal(); |
54 return signal; | 81 return signal; |
55 } | 82 } |
56 | 83 |
57 #endregion | 84 #endregion |
58 | 85 |
86 protected void CompleteResolve() { | |
87 m_state = PromiseState.Resolved; | |
88 CompleteTransit(); | |
89 } | |
90 | |
59 public Type ResultType { | 91 public Type ResultType { |
60 get { | 92 get { |
61 return typeof(void); | 93 return typeof(void); |
62 } | 94 } |
95 } | |
96 | |
97 /// <summary> | |
98 /// Выполняет обещание, сообщая об ошибке | |
99 /// </summary> | |
100 /// <remarks> | |
101 /// Поскольку обещание должно работать в многопточной среде, при его выполнении сразу несколько потоков | |
102 /// могу вернуть ошибку, при этом только первая будет использована в качестве результата, остальные | |
103 /// будут проигнорированы. | |
104 /// </remarks> | |
105 /// <param name="error">Исключение возникшее при выполнении операции</param> | |
106 /// <exception cref="InvalidOperationException">Данное обещание уже выполнено</exception> | |
107 protected void SetError(Exception error) { | |
108 if (BeginTransit()) { | |
109 m_error = error; | |
110 m_state = PromiseState.Rejected; | |
111 CompleteTransit(); | |
112 } else { | |
113 WaitTransition(); | |
114 if (m_state == PromiseState.Resolved) | |
115 throw new InvalidOperationException("The promise is already resolved"); | |
116 } | |
117 } | |
118 | |
119 protected void Rethrow() { | |
120 Debug.Assert(m_error != null); | |
121 if (m_error is OperationCanceledException) | |
122 throw new OperationCanceledException("Operation cancelled", m_error); | |
123 else | |
124 throw new TargetInvocationException(m_error); | |
63 } | 125 } |
64 | 126 |
65 public void On(Action success, Action<Exception> error) { | 127 public void On(Action success, Action<Exception> error) { |
66 AddHandler(new HandlerDescriptor(success, error)); | 128 AddHandler(new HandlerDescriptor(success, error)); |
67 } | 129 } |
70 throw new InvalidCastException(); | 132 throw new InvalidCastException(); |
71 } | 133 } |
72 | 134 |
73 public void Join() { | 135 public void Join() { |
74 WaitResult(-1); | 136 WaitResult(-1); |
137 if (IsRejected) | |
138 Rethrow(); | |
75 } | 139 } |
76 | 140 |
77 public void Join(int timeout) { | 141 public void Join(int timeout) { |
78 WaitResult(timeout); | 142 WaitResult(timeout); |
79 } | 143 } |
80 | |
81 protected void SetResult() { | |
82 if(BeginSetResult()) | |
83 EndSetResult(); | |
84 } | |
85 } | 144 } |
86 } | 145 } |
87 | 146 |