Skip to main content
Code Review

Return to Answer

Commonmark migration
Source Link

##Review

Review

##Proposed Solution

Proposed Solution

##Review

##Proposed Solution

Review

Proposed Solution

meets requirements
Source Link
dfhwze
  • 14.1k
  • 3
  • 40
  • 101

###contravariance

If you add the generic constraint where T : class you can simplify Action<T> and Action<object> because one is contravariant with the other.

Action<T> proxy = (T v) => value.Invoke(v);

 Action<T> proxy = value;

##Proposed Solution

Store all listeners in a list LinkedList(allow for duplicates).

 private List<object>LinkedList<object> listeners = new List<object>LinkedList<object>();
 private void Register(object listener)
 {
 if (listener == null) return;
 listeners.AddAddFirst(listener);
 }
 private void Unregister(object listener)
 {
 if (listener == null) return;
 listeners.Remove(listener);
 }
 public event Action<T> ChangeValue
 {
 add => Register(value);
 remove => Unregister(value);
 }
 public event Action<object> ChangeObject
 {
 add => Register(value);
 remove => Unregister(value);
 }
 public event Action ChangeEmpty
 {
 add => Register(value);
 remove => Unregister(value);
 }

Invoke event listeners using the dynamic keyword. The runtime knows which overload of InvokeChange to call. I have added one overload to take any Object as a fallback to avoid runtime exceptions, but this should be unreachable code. The combination of Reverse(), AddFirst() and Remove() ensures correct behavior. Performance is another thing though ..

 public void InvokeChange(T value)
 {
 foreach (var listener in listeners.Reverse())
 {
 Invoke((dynamic)listener, value);
 }
 }
 // these methods require equivalent method signatures ->
 // -> see comments that Action<T> and Action<object> can be combined!
 private void Invoke(Action<T> action, T value)
 {
 action.Invoke(value);
 }
 private void Invoke(Action<object> action, T value)
 {
 action.Invoke(value);
 }
 private void Invoke(Action action, T value)
 {
 action.Invoke();
 }
 private void Invoke(Object unsupportedEventListenerType, T value)
 {
 // ignore or throw exception ..
 }

###contravariance

If you add the generic constraint where T : class you can simplify Action<T> and Action<object> because one is contravariant with the other.

Action<T> proxy = (T v) => value.Invoke(v);

 Action<T> proxy = value;

##Proposed Solution

Store all listeners in a list (allow for duplicates).

 private List<object> listeners = new List<object>();
 private void Register(object listener)
 {
 if (listener == null) return;
 listeners.Add(listener);
 }
 private void Unregister(object listener)
 {
 if (listener == null) return;
 listeners.Remove(listener);
 }
 public event Action<T> ChangeValue
 {
 add => Register(value);
 remove => Unregister(value);
 }
 public event Action<object> ChangeObject
 {
 add => Register(value);
 remove => Unregister(value);
 }
 public event Action ChangeEmpty
 {
 add => Register(value);
 remove => Unregister(value);
 }

Invoke event listeners using the dynamic keyword. The runtime knows which overload of InvokeChange to call. I have added one overload to take any Object as a fallback to avoid runtime exceptions, but this should be unreachable code.

 public void InvokeChange(T value)
 {
 foreach (var listener in listeners)
 {
 Invoke((dynamic)listener, value);
 }
 }
 // these methods require equivalent method signatures ->
 // -> see comments that Action<T> and Action<object> can be combined!
 private void Invoke(Action<T> action, T value)
 {
 action.Invoke(value);
 }
 private void Invoke(Action<object> action, T value)
 {
 action.Invoke(value);
 }
 private void Invoke(Action action, T value)
 {
 action.Invoke();
 }
 private void Invoke(Object unsupportedEventListenerType, T value)
 {
 // ignore or throw exception ..
 }

##Proposed Solution

Store all listeners in a LinkedList(allow for duplicates).

 private LinkedList<object> listeners = new LinkedList<object>();
 private void Register(object listener)
 {
 if (listener == null) return;
 listeners.AddFirst(listener);
 }
 private void Unregister(object listener)
 {
 if (listener == null) return;
 listeners.Remove(listener);
 }
 public event Action<T> ChangeValue
 {
 add => Register(value);
 remove => Unregister(value);
 }
 public event Action<object> ChangeObject
 {
 add => Register(value);
 remove => Unregister(value);
 }
 public event Action ChangeEmpty
 {
 add => Register(value);
 remove => Unregister(value);
 }

Invoke event listeners using the dynamic keyword. The runtime knows which overload of InvokeChange to call. I have added one overload to take any Object as a fallback to avoid runtime exceptions, but this should be unreachable code. The combination of Reverse(), AddFirst() and Remove() ensures correct behavior. Performance is another thing though ..

 public void InvokeChange(T value)
 {
 foreach (var listener in listeners.Reverse())
 {
 Invoke((dynamic)listener, value);
 }
 }
 // these methods require equivalent method signatures ->
 // -> see comments that Action<T> and Action<object> can be combined!
 private void Invoke(Action<T> action, T value)
 {
 action.Invoke(value);
 }
 private void Invoke(Action<object> action, T value)
 {
 action.Invoke(value);
 }
 private void Invoke(Action action, T value)
 {
 action.Invoke();
 }
 private void Invoke(Object unsupportedEventListenerType, T value)
 {
 // ignore or throw exception ..
 }
updated after review of requirements, brought to attention by other reviewers
Source Link
dfhwze
  • 14.1k
  • 3
  • 40
  • 101

Store all listeners in a setlist (allow for duplicates).

 private HashSet<object>List<object> listeners = new HashSet<object>List<object>();
 private boolvoid Register(object listener)
 {
 if (listener == null) return false;return;
 return listeners.Add(listener);
 }
 private boolvoid Unregister(object listener)
 {
 if (listener == null) return false;return;
 return listeners.Remove(listener);
 }
 public event Action<T> ChangeValue
 {
 add => Register(value);
 remove => Unregister(value);
 }
 public event Action<object> ChangeObject
 {
 add => Register(value);
 remove => Unregister(value);
 }
 public event Action ChangeEmpty
 {
 add => Register(value);
 remove => Unregister(value);
 }
 public void InvokeChange(T value)
 {
 foreach (var listener in listeners)
 {
 Invoke((dynamic)listener, value);
 }
 }
 // these methods require equivalent method signatures ->
 // -> see comments that Action<T> and Action<object> can be combined!
 private void Invoke(Action<T> action, T value)
 {
 action.Invoke(value);
 }
 private void Invoke(Action<object> action, T value)
 {
 action.Invoke(value);
 }
 private void Invoke(Action action, T value)
 {
 action.Invoke();
 }
 private void Invoke(Object unsupportedEventListenerType, T value)
 {
 // ignore or throw exception ..
 }

Store all listeners in a set.

 private HashSet<object> listeners = new HashSet<object>();
 private bool Register(object listener)
 {
 if (listener == null) return false;
 return listeners.Add(listener);
 }
 private bool Unregister(object listener)
 {
 if (listener == null) return false;
 return listeners.Remove(listener);
 }
 public event Action<T> ChangeValue
 {
 add => Register(value);
 remove => Unregister(value);
 }
 public event Action<object> ChangeObject
 {
 add => Register(value);
 remove => Unregister(value);
 }
 public event Action ChangeEmpty
 {
 add => Register(value);
 remove => Unregister(value);
 }
 public void InvokeChange(T value)
 {
 foreach (var listener in listeners)
 {
 Invoke((dynamic)listener, value);
 }
 }
 // these methods require equivalent method signatures ->
 private void Invoke(Action<T> action, T value)
 {
 action.Invoke(value);
 }
 private void Invoke(Action<object> action, T value)
 {
 action.Invoke(value);
 }
 private void Invoke(Action action, T value)
 {
 action.Invoke();
 }
 private void Invoke(Object unsupportedEventListenerType, T value)
 {
 // ignore or throw exception ..
 }

Store all listeners in a list (allow for duplicates).

 private List<object> listeners = new List<object>();
 private void Register(object listener)
 {
 if (listener == null) return;
 listeners.Add(listener);
 }
 private void Unregister(object listener)
 {
 if (listener == null) return;
 listeners.Remove(listener);
 }
 public event Action<T> ChangeValue
 {
 add => Register(value);
 remove => Unregister(value);
 }
 public event Action<object> ChangeObject
 {
 add => Register(value);
 remove => Unregister(value);
 }
 public event Action ChangeEmpty
 {
 add => Register(value);
 remove => Unregister(value);
 }
 public void InvokeChange(T value)
 {
 foreach (var listener in listeners)
 {
 Invoke((dynamic)listener, value);
 }
 }
 // these methods require equivalent method signatures ->
 // -> see comments that Action<T> and Action<object> can be combined!
 private void Invoke(Action<T> action, T value)
 {
 action.Invoke(value);
 }
 private void Invoke(Action<object> action, T value)
 {
 action.Invoke(value);
 }
 private void Invoke(Action action, T value)
 {
 action.Invoke();
 }
 private void Invoke(Object unsupportedEventListenerType, T value)
 {
 // ignore or throw exception ..
 }
added 365 characters in body
Source Link
dfhwze
  • 14.1k
  • 3
  • 40
  • 101
Loading
edited terminology after remarks
Source Link
dfhwze
  • 14.1k
  • 3
  • 40
  • 101
Loading
added 245 characters in body
Source Link
dfhwze
  • 14.1k
  • 3
  • 40
  • 101
Loading
Source Link
dfhwze
  • 14.1k
  • 3
  • 40
  • 101
Loading
lang-cs

AltStyle によって変換されたページ (->オリジナル) /