Returning an event from a function - c#

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.

Related

Set Event-Handler by reflection with Type and Template argument

I would like to set an event handler only by reflection, I can get all the types but I can't achieve it.
public delegate void MyHandler<T>(IMyInterface<T> pParam);
public interface IMyInterface<T>
{
MyHandler<T> EventFired { get; set; }
}
void myFunction()
{
//admit vMyObject is IMyInterface<ClassA>
var vMyObject = vObj as IMyInterface<ClassA>;
//get the generic type => ClassA
var vTypeGeneric = vTypeReturn.GenericTypeArguments.FirstOrDefault();
//build the type handler for the event MyHandler<ClassA>
Type vAsyncOP = typeof(MyHandler<>).MakeGenericType(vTypeGeneric);
// here I don't know how to create the Event handler to set EventFired
// dynamically with the code inside
var vEventFired = vMyObject.GetType().GetProperty("EventFired");
vEventFired.SetMethod etc...
}
I found some code with the usage of Lambda/Expression but I don't understand how to use it in this case.
Full sample:
public delegate void MyHandler<T>(IMyInterface<T> pParam);
public interface IMyInterface<T>
{
MyHandler<T> EventFired { get; set; }
}
public class MyClass : IMyInterface<int>
{
public MyHandler<int> EventFired { get; set;}
}
public void ConcreteHandler(IMyInterface<int> p)
{
Console.WriteLine("I'm here");
}
void Main()
{
var myValue = new MyClass();
var deleg = Delegate.CreateDelegate(typeof(MyHandler<int>), this, "ConcreteHandler");
myValue.GetType().GetProperty("EventFired").SetValue(myValue, deleg);
// Test delegate invocation:
myValue.EventFired.Invoke(new MyClass());
}
Since the question asks about setting an event and the code refers to delegate, here is the code for setting an event using reflection (via extension method):
public delegate void MyHandler<T>(IMyInterface<T> pParam);
public interface IMyInterface<T>
{
event MyHandler<T> EventFired;
}
public class ClassA : IMyInterface<int>
{
public event MyHandler<int> EventFired;
private int _Count = 0;
public void Fire()
{
var handler = EventFired;
if (handler != null) handler(this);
}
public override string ToString()
{
return "Call: " + (++_Count).ToString();
}
}
public static class Extension
{
public static void Add<T>(this IMyInterface<T> i, System.Reflection.MethodInfo method, object method_instance = null)
{
if (method.IsGenericMethodDefinition) method = method.MakeGenericMethod(typeof(T));
Delegate d = Delegate.CreateDelegate(typeof(MyHandler<>).MakeGenericType(typeof(T)), method_instance, method);
i.GetType().GetEvent("EventFired").GetAddMethod().Invoke(i, new object[] { d });
}
}
public class Program
{
public static void Print<T>(IMyInterface<T> val)
{
string output = val.ToString();
Console.WriteLine(output);
System.Diagnostics.Debug.WriteLine(output);
}
static void Main(string[] args)
{
ClassA ca = new ClassA();
ca.EventFired += Print<int>;
ca.Add(typeof(Program).GetMethod("Print", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public));
ca.Fire();
}
}
Sorry for the title, I meant not an event but a delegate property.
I found the solution meanwhile :
public void MyDelegate<T>(IMyInterface<T> pParam)
{
}
void myFunction()
{
//admit vMyObject is IMyInterface<ClassA>
var vMyObject = vObj as IMyInterface<ClassA>;
//get the generic type => ClassA
var vTypeGeneric = vTypeReturn.GenericTypeArguments.FirstOrDefault();
//build the type handler for the event MyHandler<ClassA>
Type vAsyncOP = typeof(MyHandler<>).MakeGenericType(vTypeGeneric);
// SOLUTION here :
// Create MyDelegate<vTypeGeneric>
// Then instanciate it with CreateDelegate and typeof(IMyInterface<vTypeGeneric>)
var vMyDelegate= this.GetType().GetMethod("MyDelegate");
var vMyDelegateGeneric = vMyDelegate.MakeGenericMethod(vTypeGeneric);
Type vTypeHandlerGeneric = typeof(IMyInterface<>).MakeGenericType(vTypeGeneric);
// this => bind to method in the class
var vMethodDelegate = vMyDelegateGeneric.CreateDelegate(vTypeHandlerGeneric, this);
// Set delegate Property
var vEventFired = vMyObject.GetType().GetProperty("EventFired");
vEventFired.SetValue(value, vDelegate);
}

passing an event as an argument

I use a library[1] that defines some stuff I would like to make use of:
public delegate void FooHandler(int i);
public delegate void BarHandler(string s);
public class Foo
{
public event FooHandler Fooh;
}
public class Bar
{
public event BarHandler Barh;
}
I would like to have a short term memory, that I can "attach" to these events:
public class ShortTermMemory<T>
{
public ShortTermMemory(??? arg)
{
arg += t => Remeber = t;
}
public T Remember { get; private set; }
}
and attach them somewhere like
var foo = new Foo();
var bar = new Bar();
var intmemory = new ShortTermMemory<int>(foo.Fooh);
var stringmemory = new ShortTermMemory<string>(bar.Barh);
This is impossible because:
??? is (somewhat understandably) not a valid type declaration, and
"The event can only be used on the left hand side of += or -="
Is there anything I can do to fix this, or is this fundamentally impossible in C#? I would like to have compile time guarantees that ShortTermMemory is only "fed" by one event source, which is known at compile time to have a single argument of type T.
[1]: Example implementation for demonstration purposes only
With the compile time guarantees you are expecting it isn't possible in C#. There are a few problems there:
events are backed by a private delegate field which has a combined invocation list. This is considered an implementation detail, thus the private access.
We need to reference the event's delegate field to apply add and remove (+=/-=) operators with Delegate.Combine/Remove.
As C# handles delegates as own types, we should have a generic definition of both FooHandler and BarHandler.
You're missing an unsubscription from the event, possibly placed in the destructor of ShortTermMemory`1. At this time, the event object may not exist anymore, see How to save a ref variable for later use?
Working solution:
public delegate void Handler<T> ( T i );
public class Foo
{
public event Handler<int> Fooh;
public void Set(int i) {
if (Fooh != null) {
Fooh(i);
}
}
}
public class ShortTermMemory<T>
{
object obj = null;
string eventName;
Handler<T> handler;
public ShortTermMemory (object obj, string eventName) {
this.obj = obj;
this.eventName = eventName;
this.handler = new Handler<T>(Set);
Type type = obj.GetType();
EventInfo info = type.GetEvent(eventName);
info.AddEventHandler(obj, handler);
}
~ShortTermMemory() {
if (obj != null) {
Type type = obj.GetType();
EventInfo info = type.GetEvent(eventName);
info.RemoveEventHandler(obj, handler);
}
}
public T Remember { get; set; }
public void Set(T t) {
Remember = t;
}
}
var foo = new Foo();
var intmemory1 = new ShortTermMemory<int>(foo, "Fooh");
var intmemory2 = new ShortTermMemory<int>(foo, "Fooh");
foo.Set(10);

Create Dictionary for delegates and events

I want to create a dictionary like this:
public class MyClass
{
public delegate void CreateClickEvent(string value);
public event CreateClickEvent OnCreateClick;
public delegate void CreateHoverEvent(string value);
public event CreateHoverEvent OnCreateHover;
private Dictionary<string,Delegate> _myDictionary = null;
public MyClass()
{
_myDictionary = new Dictionary<string,Delegate>();
_myDictionary.Add("Click", OnCreateClick);
_myDictionary.Add("Hover", OnCreateHover);
}
public void Call(string name)
{
Delegate action;
if (_myDictionary.TryGetValue(name, out action))
{
if (action != null)
action.DynamicInvoke( "something" );
else
Console.WriteLine("null");
}
else
Console.WriteLine("Couldn't find action");
}
}
public class Tester()
{
public Tester()
{
MyClass MyClass = new MyClass();
myClass.OnCreateClick += RaiseCreateClickEvent;
myClass.OnCreateHover += RaiseCreateHoverEvent;
}
public void RaiseCreateClickEvent(string value)
{
///do it here
}
public void RaiseCreateHoverEvent(string value)
{
///do it here
}
}
but unfortunately, the method RaiseCreateClickEvent or RaiseCreateHoverEvent (class Tester) is not calling from Call method (class MyClass). And it's not giving any error and action variable is looking null and printing null.
What am I doing wrong here?
You have dictionary of delegates, but it keeps values of your events at the moment of creation of the dictionary. At that point both OnCreateXXXX are null.
As an option can use dictionary of Action and call event in each so action will use current value of the event, not the initial one:
private Dictionary<string,Action<string>> _myDictionary =
new Dictionary<string,Action<string>>();
_myDictionary.Add("Click", s => OnCreateClick(s));
_myDictionary.Add("Hover", s => OnCreateHover(s));
And use:
_myDictionary["Click"] ("sometext");
Note good reading on delegates (and especially how + / += impacts value) is available http://csharpindepth.com/Articles/Chapter2/Events.aspx

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.

Observable.From for future events instead of subject

how can i implement this situation in RX without using subject. I've read a lot, and I just can't seem to figure it out
public class Member
{
public int Id { get; private set; }
public string Email { get; private set; }
public Member(string email)
{
this.Email = email;
}
}
public class MemberRepository
{
public void AddMember(Member member)
{
// save member
memberAdded.OnNext(member);
}
private Subject<Member> memberAdded = new Subject<Member>();
public IObservable<Member> MemberAdded { get { return memberAdded.AsObservable(); } }
}
public class MemberController
{
public void Create(Member item)
{
var repository = new MemberRepository();
var subs = repository.MemberAdded.Subscribe(x => SendMail(x));
repository.AddMember(item);
}
private void SendMail(Member value)
{
// send welcome mail
}
}
I've don't know how to initialize the IObservable MemberAdded because it is always null if it doesn't have the Subject backer nor do I know how to later call the OnNext at from a later function.
Lastly, is it a problem to have the observables as static properties and all the subscription code in one place?
The way I have implemented something similar is to expose a normal C# event MemberAdded on my MemberRepository. You can then use Observable.FromEvent or Observable.FromEventPattern (the difference is here) to subscribe to the event something like this:
public class MemberRepository
{
public void AddMember(Member member)
{
// save member
if (MemberAdded != null)
MemberAdded(new MemberEventArgs(member, MemberEvent.Add));
}
public event EventHandler<MemberEventArgs> MemberAdded;
}
...
Observable.FromEventPattern<MemberEventArgs>(h => memberRepository.MemberAdded += h,
h => memberRepository.MemberAdded -= h)
.Select(e => e.Member)
.Subscribe(m => Console.WriteLine("Member "+m+" added!));
In regard to your second question, you should avoid static properties - consider using something like the Event Aggregator pattern instead

Categories