Rx Extensions: How do I make a subscription dependent on another subscription? - c#

I have a class that takes an observable in its constructor, then subscribes to it and does some stuff, sets properties etc. The class itself is observable.
I want to subscribe to my source observable only if someone is subscribed to my class, but I can't figure out how to do it.
public MyClass : IObservable<MyResult>
{
private readonly Subject<MyResult> _subject = new Subject<MyResult>();
private readonly IConnectableObservable<MySource> _source;
public MyClass(IObservable<MySource> source)
{
_source = source
//All my logic to set properties and such
//goes here as a side effect, instead of in a subscription...
.Do(...)
//I hope that by publishing, side effects will happen only once...
.Publish();
}
public IDisposable Subscribe(IObserver<MyResult> observer)
{
return new CompositeDisposable(
_source.Subscribe(/*
don't have anything to do here,
just subscribing to make sure I'm subscribed to source...
(this can't be the right way to do it)
*/),
_subject.Subscribe(observer));
}
}
UPDATE
#Scott: I can see why implementing IObservable would be an anti-pattern. My Class needs to consume a single observable, and exposes 3 as properties (originally the most commonly used observable was going to be returned by MyClass itself, but I think that having it as a property might be better.
What I'm trying to write is an observable ICommand. I know some exist, but this is more of a way to learn Rx...
public class ObservableCommand<T> : ICommand
{
private readonly ISubject<T> _executeRequests = new Subject<T>();
private readonly ISubject<T> _canExecuteRequests = new Subject<T>();
public IObservable<bool> CanExecuteChanges { get; private set; }
public IObservable<T> CanExecuteRequests { get; private set; }
public IObservable<T> ExecuteRequests { get; private set; }
public ObservableCommand(IObservable<bool> canExecute)
{
var source = canExecute.DistinctUntilChanged()
//How do I dispose of subscription later?
//I have this fear that I'm going to have a chain of references,
//and my entire app will never get GC'd!
var subscription = source.Subscribe(
o => {
if (CanExecuteChanged != null)
CanExecuteChanged(this, EventArgs.Empty);
});
CanExecuteChanges = source;
CanExecuteRequests = _canExecuteRequests.AsObservable();
ExecuteRequests = _executeRequests.AsObservable();
}
#region ICommand Members
public bool CanExecute(object parameter)
{
_canExecuteRequests.OnNext(parameter is T ? (T)parameter : default(T));
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_executeRequests.OnNext(parameter is T ? (T)parameter : default(T));
}
#endregion
}

How about just not Doing or Publishing in the constructor, but rather in the Subscribe method?
It should be said, explicitly implementing IObservable<T> is something of an Rx anti-pattern.
You can make Subscriptions dependent on other subscribers with Defer and Create, something like
IObservable<MySource> source;
IObservable<MySource> sourceWithSubSideEffect = Observable.Defer(() =>
{
// Do something interesting on Subscription
// ....
return source;
});

I've prepared a snipped for you. MyClass implements IObservable<T> and has also methods of IObserver<T> but they are all private. With additional OnInitialize and OnSubscribe you should be able to do whatever you want on any event you want to response to.
If you want to make this snipped reusable you could define all methods as partial as they all return void. Then you could create definition to whatever you want.
public class MyClass<T> : IObservable<T>
{
private readonly IObservable<T> m_Source;
public MyClass(IObservable<T> source)
{
if (source == null) throw new ArgumentNullException("source");
m_Source = source.Do(OnNext, OnError, OnCompleted);
OnInitialize();
}
public IDisposable Subscribe(IObserver<T> observer)
{
OnSubscribe();
return m_Source.Subscribe(observer);
}
private void OnInitialize()
{
Console.WriteLine("OnInitialize");
}
private void OnSubscribe()
{
Console.WriteLine("OnSubscribe");
}
private void OnNext(T value)
{
Console.WriteLine("OnNext: {0}", value);
}
private void OnError(Exception error)
{
Console.WriteLine("OnError: {0}", error.Message);
}
private void OnCompleted()
{
Console.WriteLine("OnCompleted");
}
}

Related

Handling batches of Commands

I have an architecture like the one described in this blog post. In summary, I have command objects, e.g. :
public class MoveCustomerCommand : ICommand
{
public int CustomerId { get; set; }
public Address NewAddress { get; set; }
}
And command handlers for each command which derive from the interface ICommandHandler<TCommand>:
public interface ICommandHandler<TCommand> where TCommand : ICommand
{
void Handle(TCommand command);
}
public class MoveCustomerCommandHandler : ICommandHandler<MoveCustomerCommand>
{
public void Handle(MoveCustomerCommand command)
{
// Logic here
}
}
Now I'm looking for a clean solution to the following use case: Some clients produce a batch of heterogenous commands that need to be processed. In other words, I want to implement the following:
void HandleBatch(List<ICommand> batch) {
}
I have some ideas but I'm not convinced that any of them is good enough.
Option 1 Put a humongous switch-case in the HandleBatch function.
void HandleBatch(List<ICommand> batch) {
foreach (var command in batch) {
switch (command) {
case MoveCustomerCommand cmd:
new MoveCustomerCommandHandler().Handle(cmd);
break;
case DeleteCustomerCommand cmd:
new DeleteCustomerCommandHandler().Handle(cmd);
break;
// ....
}
}
}
Option 2 Use reflections to find the appropriate command handler for each command.
void HandleBatch(List<ICommand> batch) {
foreach (var command in batch) {
var commandType = command.GetType();
var handlerInterface = typeof(ICommandHandler<>)
.MakeGenericType(new Type[]{commandType});
// Search the current assembly for a type that implements "handlerInterface"
var handlerType = Assembly.GetAssembly(this.GetType())
.GetTypes()
.Where(t => t != handlerInterface &&
handlerInterface.IsAssignableFrom(t)
).First();
var handler = CreateInstance(handlerType);
handler.Handle(command);
}
}
Option 3 Same as option 2, but also annotate all the Handlers with a custom annotation and when searching for the type filter by annotation as well.
Option 4 Something else?
Another inconvenience is that the HandleBatch will have to have handy an instance of virtually every possible dependency since most of the logic of the application is in these commands. But I guess I can't go around this.
Ok. Suppose you have the following commands:
public class MoveCustomerCommand : ICommand
{
public int CustomerId { get; set; }
public bool CanExecute(object parameter) => true;
public void Execute(object parameter) { }
public event EventHandler CanExecuteChanged;
}
public class KillCustomerCommand : ICommand
{
public int CustomerId { get; set; }
public bool CanExecute(object parameter) => true;
public void Execute(object parameter) { }
public event EventHandler CanExecuteChanged;
}
Now consider the following architecture proposal for the handlers:
public abstract class CommandHandlerBase
{
protected static readonly Dictionary<Type, CommandHandlerBase> _handlers = new Dictionary<Type, CommandHandlerBase>();
protected abstract void HandleCommand<TCommand>(TCommand command) where TCommand: ICommand;
public static void Handle<TCommand>(TCommand command) where TCommand : ICommand
{
if (_handlers.TryGetValue(typeof(TCommand), out var handler))
{
handler.HandleCommand(command);
}
}
}
public abstract class CommandHandlerBase<TCommandHandlerBase, TCommand> : CommandHandlerBase
where TCommandHandlerBase : CommandHandlerBase<TCommandHandlerBase, TCommand>, new() where TCommand : ICommand
{
public static void Register()
{
var type = typeof(TCommand);
_handlers[type] = new TCommandHandlerBase();
}
protected override void HandleCommand<T>(T command) => Handle((TCommand) (object) command);
public abstract void Handle(TCommand command);
}
Basically what we do is to centralize all the handling into one base class, and we provide just an entry point for handling any TCommand (provided that there is a handler registered, you can put a default case or just crash if no handler is found).
The implementation may look confusing at first sight, but the usage is really nice after: we only define our handlers classes and we call Register. Let's see how they look:
public class MoveCustomerCommandHandler : CommandHandlerBase<MoveCustomerCommandHandler, MoveCustomerCommand>
{
public override void Handle(MoveCustomerCommand command) => Console.WriteLine("Moving the customer");
}
public class KillCustomerCommandHandler : CommandHandlerBase<KillCustomerCommandHandler, KillCustomerCommand>
{
public override void Handle(KillCustomerCommand command) => Console.WriteLine("Killing the customer");
}
And testing:
private static void Main(string[] args)
{
MoveCustomerCommandHandler.Register();
KillCustomerCommandHandler.Register();
CommandHandlerBase.Handle(new MoveCustomerCommand());
CommandHandlerBase.Handle(new KillCustomerCommand());
Console.ReadLine();
}
I think this approach is more maintainable and scalable, no need for reflection (with its performance hit), no need for very big switchs statements or hardcoded solutions.
Furthermore, you can add later an unregister method, or to keep more than one handler for a given command, the limit is the sky.. =)

Returning Disposable from Subscribe method for an Observable

I have a question on Observables (which I posted on the publishers sub forum for this book but I am still waiting on any response).
I use the helper methods provided as is the standard practice rather than handcrafting the observables. However just out of academic interest I did see into what it takes to handcraft an observable.
I saw an implementation in a book where at the end of subscribe method Disposable.Empty was returned.
The code is somewhat like below.
public class MyObservable : IObservable<int>
{
public IDisposable Subscribe(IObserver<int> observer)
{
for (int i = 0; i < 5; i++)
{
Thread.Sleep(1000);
observer.OnNext(i);
}
observer.OnCompleted();
return Disposable.Empty;
}
}
If I want to return a proper Disposable which will actually lead to unsubscribing when Dispose is called what should be the way?
I had a crack at it using this for the Observable and this for Observer
I had to introduce a subscription handler
public class SubscriptionHandler : IDisposable
{
private readonly List<IObserver<int>> _listOfObservers;
private readonly IObserver<int> _currentObserver;
public SubscriptionHandler(List<IObserver<int>> currentListOfObservers, IObserver<int> currentObserver)
{
_listOfObservers = currentListOfObservers;
_currentObserver = currentObserver;
}
public void Dispose()
{
if (_currentObserver != null && _listOfObservers.Contains(_currentObserver))
{
_listOfObservers.Remove(_currentObserver);
}
}
}
This is the code for the Observable
public class MyObservable : IObservable<int>
{
private List<IObserver<int>> _listOfSubscribedObservers = new List<IObserver<int>>();
public IDisposable Subscribe(IObserver<int> observer)
{
if (!_listOfSubscribedObservers.Contains(observer))
{
_listOfSubscribedObservers.Add(observer);
}
Task.Run(() =>
{
for (int i = 0; i < 5; i++)
{
Thread.Sleep(1000);
observer.OnNext(i);
}
observer.OnCompleted();
});
return new SubscriptionHandler(_listOfSubscribedObservers, observer);
}
}
I have a feeling that I am missing something. There has to be a built in way to return a meaningful Disposable for handcrafted Observable or this is something which comes only with Observable create helper methods?
I should make clear that all of this is a demonstration of Rx design internals. You can have a look at classes AnonymousObservable<T>,
AnonymousObserver<T>, and AnonymousDisposable, which is how the framework does it. Pretty straight forward. However, you should almost never use any of this code, rather use things like Disposable.Create and Observable.Create. If you're implementing an IObservable, you're almost definitely doing it wrong.
Here's the basic idea: The observable needs to produce an IDisposable which removes the relevant observer from the observable's internal list of observers. Your code is (wrongly) removing all observers from the internal list.
Here's a basic disposable which makes it easy to create functionally. With this code, GenericDisposable.Create is the same as Disposable.Create(Action a).
public class GenericDisposable : IDisposable
{
public static IDisposable Create(Action disposeAction)
{
return new GenericDisposable(disposeAction);
}
private readonly Action _disposeAction;
public GenericDisposable(Action disposeAction)
{
_disposeAction = disposeAction;
}
public void Dispose()
{
_disposeAction();
}
}
...and here's an example observable implementation:
public class SendIntMessages : IObservable<int>
{
private readonly HashSet<IObserver<int>> _observers = new HashSet<IObserver<int>>();
protected void OnNext(int i)
{
foreach (var o in _observers)
o.OnNext(i);
}
protected void OnError(Exception e)
{
foreach (var o in _observers)
o.OnError(e);
}
protected void OnCompleted()
{
foreach (var o in _observers)
o.OnCompleted();
}
public void SendIntMessage(int i)
{
OnNext(i);
}
public void EndStream()
{
OnCompleted();
}
public void SendError(Exception e)
{
OnError(e);
}
public IDisposable Subscribe(IObserver<int> observer)
{
_observers.Add(observer);
return GenericDisposable.Create(() => _observers.Remove(observer));
}
}
This is a long-running, hot observable. It keeps track of its observers, and the disposable unsubscribes them.
Consider in contrast this observable:
public class CountTo5 : IObservable<int>
{
public IDisposable Subscribe(IObserver<int> observer)
{
observer.OnNext(1);
observer.OnNext(2);
observer.OnNext(3);
observer.OnNext(4);
observer.OnNext(5);
return GenericDisposable.Create(() => {});
}
}
This is a 'cold' observable that runs immediately. There's no way to unsubscribe in the middle: By the time you get the disposable, the observable has concluded.
Disposable.Empty is a simple short hand for DisposableCreate(() => {}).
To return a meaningful IDisposable to the caller, you should not generate all notifications synchronously during the subscription. You should generate them asynchronously on a different context, and return to the caller immediately a subscription that has not completed yet. Here is a way to do it, by using the Task.Run method to invoke the notifications on the ThreadPool:
public class MyObservable : IObservable<int>
{
public IDisposable Subscribe(IObserver<int> observer)
{
var cts = new CancellationTokenSource();
_ = Task.Run(async () =>
{
for (int i = 0; i < 5; i++)
{
await Task.Delay(1000, cts.Token);
observer.OnNext(i);
}
observer.OnCompleted();
}, cts.Token);
return new CancellationDisposable(cts);
}
}
The CancellationDisposable class...
Represents a disposable resource that has an associated CancellationToken that will be set to the cancellation requested state upon disposal.

Pattern for 'routing' events through several subscribers?

I have a group of classes with the following interface:
public interface RoutedEventReceiver<T>
{
IDisposable Apply(IObservable<T> stream);
bool ShouldForwardEvent(T anEvent);
}
What I would like to do is to maintain a stack of these classes, with each event being filtered through the ShouldForwardEvent(T) predicate, and the resulting IObservable<T> passed to the next receiver. I also want to be able to push and pop new receivers while my program is running (at some point I may want to move from a stack to some other collection but for now a stack is sufficient).
What I have currently does work, but I don't feel like it is very "Rx". I am sure there must be a way to do what I want without all this imperative logic:
private void Refresh()
{
// _subscriptions is a list of previous subscriptions
foreach (var subscription in _subscriptions)
subscription.Dispose();
_subscriptions.Clear();
// _stream is my stream of incoming events
if (_stream != null)
{
var stream = _stream;
foreach (var eventReceiver in _eventReceivers)
{
// add the subscription so it can be disposed next Refresh()
_subscriptions.Add(eventReceiver.Apply(stream));
// filter the stream for the next event receiver
stream = stream.Where(eventReceiver.ShouldForwardEvent);
}
}
}
The above method is called whenever I Push or Pop on the stack.
Is there a cleaner, more functional way to express the above intent? I have tried .Publish() but with little success - perhaps I don't know it well enough.
I have managed to make the Publish approach work, but it doesn't afford me much other than getting rid of the need to keep a list of IDisposables:
private void Refresh()
{
_published.DisposeIfNotNull();
if (_stream != null)
{
var connectable = _stream.Publish();
_published = connectable.Connect();
var stream = connectable.AsObservable();
foreach (var eventReceiver in _eventReceivers)
{
eventReceiver.Apply(stream);
stream = stream.Where(eventReceiver.ShouldForwardEvent);
}
}
}
The class below (named CORStack for Chain Of Responsibility* Stack), tries to do what you're after. Internally it adds an ShouldHandle bool to the stream and uses this to determine whether to process. It exposes the standard Push, Pop, and Peek methods.
public sealed class CORStack<T>
{
Stack<StackFrame> _handlers;
public CORStack(IObservable<T> source)
{
_handlers = new Stack<StackFrame>();
_handlers.Push(new StackFrame(
source.Select(t => new ShouldHandleWrapper(t, true)),
new Handler<T>(new Action<T>(t => { }), true)));
}
public void Push(Handler<T> handler)
{
_handlers.Push(new StackFrame(_handlers.Peek().Observable, handler));
}
public Handler<T> Peek()
{
return _handlers.Peek().Handler;
}
public Handler<T> Pop()
{
var frame = _handlers.Pop();
frame.Dispose();
return frame.Handler;
}
class StackFrame : IDisposable
{
IDisposable _unsub;
public IObservable<ShouldHandleWrapper> Observable { get; private set; }
public Handler<T> Handler { get; private set; }
public StackFrame(IObservable<ShouldHandleWrapper> topOfStack, Handler<T> handler)
{
_unsub = topOfStack.Subscribe(shouldHandle =>
{
if (shouldHandle.ShouldHandle)
handler.Action.Invoke(shouldHandle.Value);
});
Observable = topOfStack.Select(shouldHandle =>
new ShouldHandleWrapper(shouldHandle.Value, shouldHandle.ShouldHandle && handler.Forward));
Handler = handler;
}
public void Dispose()
{
_unsub.Dispose();
}
}
class ShouldHandleWrapper
{
public readonly T Value;
public readonly bool ShouldHandle;
public ShouldHandleWrapper(T value, bool shouldHandle)
{
Value = value;
ShouldHandle = shouldHandle;
}
}
}
public class Handler<T>
{
public Action<T> Action { get; set; }
public bool Forward { get; set; }
public Handler(Action<T> action, bool forward)
{
Action = action;
Forward = forward;
}
}
*I realised that it's not a chain of responsibility, but can't think of a better name atm.
This is a case where I'd actually use Subjects. Create a subject for each handler, then subscribe to the stream and loop through the handlers passing the event as required. This avoids continually unsubscribing/resubscribing to the stream (and thus the Refresh method), which is not always appropriate. We use lock to guard against a new receiver being added or removed at the same moment as a new value is coming through the stream. If you can guarantee that cannot happen, then you can remove the lock statements.
public class YourClass<T> : IDisposable
{
private readonly Stack<Tuple<Subject<T>, RoutedEventReceiver<T>, IDisposable> _handlers;
private readonly IObservable<T> _stream;
private readonly IDisposable _streamSubscription;
public YourClass(IObservable<T> stream)
{
_handlers = new Stack<Tuple<Subject<T>, RoutedEventReceiver<T>, IDisposable>();
_stream = stream;
_streamSubscription = stream.Subscribe(OnNext, OnError, OnCompleted);
}
public void Dispose()
{
_streamSubscription.Dispose();
lock (_handlers)
{
foreach (var h in _handlers)
{
h.Item3.Dispose();
h.Item1.Dispose();
}
_handlers.Clear();
}
}
private void OnNext(T value)
{
lock (_handlers)
{
for (var h in _handlers)
{
h.Item1.OnNext(value);
if (!h.Item2.ShouldForwardEvent(value)) break;
}
}
}
private void OnError(Exception e)
{
lock (_handlers)
{
for (var h in _handlers) { h.Item1.OnError(e); }
}
}
private void OnCompleted()
{
lock (_handlers)
{
for (var h in _handlers) { h.Item1.OnCompleted(); }
}
}
public void Push(RoutedEventReceiver<T> handler)
{
lock (_handlers)
{
var subject = new Subject<T>;
_handlers.Push(Tuple.Create(subject, handler, handler.Apply(subject)));
}
}
public RoutedEventReceiver<T> Pop()
{
lock (_handlers)
{
var handler = _handlers.Pop();
handler.Item3.Dispose();
handler.Item1.Dispose();
return handler.Item2;
}
}
}

How to implement an event using Reactive Extensions

The Reactive Extensions allow you to easily subscribe to an event using Observable.FromEventPattern, but I can't find anything on how you might implement an event when you have an IObservable.
My situation is this: I need to implement an interface which contains an event. That event is supposed to be called whenever a certain value of my object changes, and for thread safety reasons I need to call this event on a certain SynchronizationContext. I am also supposed to call each event handler with the current value on registration.
public interface IFooWatcher
{
event FooChangedHandler FooChanged;
}
Getting an observable that does what I want is rather easy with Rx using BehaviorSubject:
public class FooWatcher
{
private readonly BehaviorSubject<Foo> m_subject;
private readonly IObservable<Foo> m_observable;
public FooWatcher(SynchronizationContext synchronizationContext, Foo initialValue)
{
m_subject = new BehaviorSubject<Foo>(initialValue);
m_observable = m_subject
.DistinctUntilChanged()
.ObserveOn(synchronizationContext);
}
public event FooChangedHandler FooChanged
{
add { /* ??? */ }
remove { /* ??? */ }
}
}
Now I am looking for an easy way to have the add and remove functions subscribe and unsubscribe the passed FooChangedHandler as an Observer<Foo> on m_observable. My current implementation looks similar to this:
add
{
lock (m_lock)
{
IDisposable disp = m_observable.Subscribe(value);
m_registeredObservers.Add(
new KeyValuePair<FooChangedHandler, IDisposable>(
value, disp));
}
}
remove
{
lock (m_lock)
{
KeyValuePair<FooChangedHandler, IDisposable> observerDisposable =
m_registeredObservers
.First(pair => object.Equals(pair.Key, value));
m_registeredObservers.Remove(observerDisposable);
observerDisposable.Value.Dispose();
}
}
However, I hope to find an easier solution, because I need to implement several of these events (of differing handler types). I tried to roll my own generic solution but it creates some additional problems that need to be worked around (in particular, how you generically work with a delegate that takes a parameter of T), so I would prefer to find an existing solution that bridges the gap in this direction - just as FromEventPattern does the reverse.
You could do this:
public event FooChangedHandler FooChanged
{
add { m_observable.ToEvent().OnNext += value; }
remove { m_observable.ToEvent().OnNext -= value; }
}
However, on the remove, I think perhaps you just may want to dispose of the subscription ... or perhaps get the Action from ToEvent() and store that as a member. Untested.
EDIT: You'll have to use Action instead of a FooChangedHandler delegate, however.
EDIT 2: Here's a tested version. I suppose you need to use FooChangedHandler, however, since you have a bunch of these pre-existing handlers?
void Main()
{
IObservable<Foo> foos = new [] { new Foo { X = 1 }, new Foo { X = 2 } }.ToObservable();
var watcher = new FooWatcher(SynchronizationContext.Current, new Foo { X = 12 });
watcher.FooChanged += o => o.X.Dump();
foos.Subscribe(watcher.Subject.OnNext);
}
// Define other methods and classes here
//public delegate void FooChangedHandler(Foo foo);
public interface IFooWatcher
{
event Action<Foo> FooChanged;
}
public class Foo {
public int X { get; set; }
}
public class FooWatcher
{
private readonly BehaviorSubject<Foo> m_subject;
public BehaviorSubject<Foo> Subject { get { return m_subject; } }
private readonly IObservable<Foo> m_observable;
public FooWatcher(SynchronizationContext synchronizationContext, Foo initialValue)
{
m_subject = new BehaviorSubject<Foo>(initialValue);
m_observable = m_subject
.DistinctUntilChanged();
}
public event Action<Foo> FooChanged
{
add { m_observable.ToEvent().OnNext += value; }
remove { m_observable.ToEvent().OnNext -= value; }
}
}
Given that you are already mixing the boundaries between reactive and more normal code, you could do a less reactive version. To start simply declare a normal event pattern
public event FooChangedHandler FooChanged;
protected void OnFooChanged(Foo)
{
var temp = FooChanged;
if (temp != null)
{
temp(new FooChangedEventArgs(Foo));
}
}
and then simply connect the observable to it in the constructor
m_Observable.Subscribe(foo => OnFooChanged(foo));
It's not very Rx but it is incredibly simple.

Returning an event from a function

What is the syntax to return an event from a function? (Not to call the event, to return it so that it can be bound to functions).
I have a container class that contains a dictionary where each members has an event.
The aim is to be able to write something like this:
Container c = new Container();
c.CreateEventForKey("a"); // Create the member in the dictionary
c.EventForKey("a") += some_function; // Bind some_function to the event in the "a" member
c.OnEventForKey("a","b"); // Calls some_function with argument "b"
The Container class looks like this:
public class Container {
public class Member {
public event Action<string> AnEvent;
public void OnEvent( string v ) { if(AnEvent!=null) { AnEvent(v); } }
}
protected Dictionary<string,Member> members;
// This seems to work OK.
public void OnEventForKey(string k, string v) {
if ( members.ContainsKey(k) ) { members[k].OnEvent(v); }
else { /* report error */ }
}
// Can't get this to compile.
public event Action<string> EventForKey(string k ) {
if ( members.ContainsKey(k) ) { return members[k].AnEvent; }
else { /* report error */ }
}
}
How can I define EventForKey so that this does what I expect?
What is the syntax to return an event from a function?
You can't, easily. Events - like properties - aren't really first class "objects" as such; they're members of a class. You don't really have a class member here - you're trying to just keep delegates in a dictionary.
You could create your own "event-like" container, but it's probably better to consider alternative designs, e.g.
c.Subscribe("a", SomeFunction);
c.OnEventForKey("a");
You might want to look at EventHandlerList for inspiration.
Why not simply return member and subscribe to it's event?
public IMember MemberForKey(string key) // return IMember
{
if (!members.ContainsKey(key))
throw new Exception();
return members[key];
}
And then subscribe:
Container c = new Container();
c.CreateEventForKey("a");
c.MemberForKey("a").AnEvent += some_function;
c.OnEventForKey("a", "b");
But you have public OnEvent method in Member class. In order to forbid raising events by client, you can create interface which will show only event. Just implement this interface by Member class:
public interface IMember
{
event Action<string> AnEvent;
}
And yes, you cannot return event, because actually event is not object, it is set of two methods add and remove, which add and remove delegates to inner field of delegate type. Here is how your event looks like:
private Action<string> _action; // field of delegate type
public event Action<string> AnEvent
{
add { _action += value; }
remove { _action -= value; }
}
Purpose of event is to provide only two operations for clients - adding and removing handlers. Delegate itself is hidden to clients. You can make it public:
public Action<string> _action;
But in this case any client can invoke it.
UPDATE: if you want to go with Subscribe/Remove syntax, then just use dictionary with handlers:
public class Container
{
private Dictionary<string, Action<string>> handlers =
new Dictionary<string, Action<string>>();
public void CreateEventForKey(string key)
{
// with empty handler added you can avoid null check
handlers.Add(key, (value) => { });
}
public void OnEventForKey(string key, string value)
{
if (!handlers.ContainsKey(key))
throw new Exception();
handlers[key](value);
}
public void Subscribe(string key, Action<string> handler)
{
if (!handlers.ContainsKey(key))
throw new Exception();
handlers[key] += handler;
}
}
Here's complete working example:
class Program
{
static void Main(string[] args)
{
Container c = new Container();
c.CreateEventForKey("a"); // Create the member in the dictionary
c.EventForKey("a").Add(str => Console.WriteLine(str));
c.EventForKey("a").Add(str => Console.WriteLine(str.ToUpper()));
c.OnEventForKey("a", "baa baa black sheep");
Console.ReadLine();
}
}
public class Container
{
public class Member
{
public List<Action<string>> AnEvent = new List<Action<string>>();
public void OnEvent(string v)
{
if (AnEvent != null)
{
this.AnEvent.ForEach(action => action(v));
}
}
public void AddEvent(Action<string> action)
{
this.AnEvent.Add(action);
}
}
protected Dictionary<string, Member> members = new Dictionary<string,Member>();
public void CreateEventForKey(string key)
{
this.members[key] = new Member();
}
// This seems to work OK.
public void OnEventForKey(string k, string v)
{
if (members.ContainsKey(k)) { members[k].OnEvent(v); }
else { /* report error */ }
}
public List<Action<string>> EventForKey(string k)
{
if (members.ContainsKey(k)) { return members[k].AnEvent; }
else { throw new KeyNotFoundException(); }
}
}
The difference is to behave similarly to an event by using a list of delegates.

Categories