I have recently started working with C# events and I am really liking the ease of use they offer (I come from a java background where we have to do all this event stuff manually).
However, there is one thing from my java background that I am missing: the inheritance side.
In java, if you want to subscribe to an event, you would inherit an interface such as IKeyListener. The interface would contain all of the method event signatures which you would then implement in the subscribing class. Whenever a key would be pressed, these implemented methods would be fired. Much the same as C#. However, unlike in java, I am unable to identify which classes subscribe to certain events because they don't actually inherit anything.
So if I wanted a list of objects which have key press event support I could do
List<IKeyListener> keyListeners = new ArrayList<IKeyListener>();
However, I don't see any good way to do this in C#. How would I be able to create list similar to the one above? Preferably without much "hackiness".
Thank you.
In C# you can define the event in an interface like this:
public interface IDrawingObject
{
event EventHandler ShapeChanged;
}
Then you can do what you want and store them like this:
var shapes = new List<IDrawingObject>();
A class can then implement the interface like this:
public class Shape : IDrawingObject
{
public event EventHandler ShapeChanged;
void ChangeShape()
{
// Do something here before the event…
OnShapeChanged(new MyEventArgs(/*arguments*/));
// or do something here after the event.
}
protected virtual void OnShapeChanged(MyEventArgs e)
{
if(ShapeChanged != null)
{
ShapeChanged(this, e);
}
}
}
So in other words the event becomes part of the interface and if a class implements that interface, the class must provide an implementation for the event as well. That way you are safe to assume the implementing class has the event.
Finally every event will need to share some info about the event. That class can inherit the EventArgs class like below:
public class MyEventArgs : EventArgs
{
// class members
}
Related
I do not know if there is an answer to this - I can not seem to find examples so maybe my terminology is not right or maybe this should not be done so forgive me for asking.
I have a base class with an object that has several events and event handling code - basically this is a boiler plate process using a FileSystemWatcher.
In my base I have all the code wired up for handling particular events and error handling.
The issue is that I am looking to be able to control what events of file system watcher the base class should subscribe to (was thinking to include all and use a switch case to add them) but then I need to handle them in the derived class and not in the base - because there is specific functionality of the derived classes that I want. I do not want to implement all the events in the base if possible - because I do not want the overhead when 4 to 8 of these derived classes are running. One thing I would like is force a derived class to SUBSCRIBE to an event.
I know from DCcoder that abstract was key in forcing methods to be 'must inherit' but I am at a loss on forcing the subscription.
public abstract class myBase
{
public event EventHandler<string> MessageAvailable;
protected void OnMessageAvailable(string e)
{
MessageAvailable?.Invoke(this, e);
}
public event EventHandler<Exception> Error;
protected virtual void OnError(Exception e)
{
Error?.Invoke(this, e);
}
}
public myderivedclass : myBase
{
this.Message += IfYouwantTo;
this.Error += REQUIRE_THIS_SUBSCRIPTION_HandleErrorHere;
}
DerivedClass needs to actually handle the events so do I create an empty event handler in the base class and use an interface to force my derived class to override the base or rather than that force the derived class to implement the handler ??
Or am I going about this all wrong ?
Any examples are appreciated ..
I'm adding a replaying feature to my game. Having this feature, I can capture user's input to the game and feed them back to Unity later on for replaying the game. But the design of VRStandardAssets.Utils.VRInput class prevents me to mimic user inputs.
This class does not provide any public method to make it possible to trigger its events (e.g. OnClick or OnDoubleClick events) programmatically. So I decided to create a derived class from it and write my own public methods to trigger the events. This strategy failed because VRInput's methods are private meaning that I cannot invoke them from a derived class.
It is recommended for this type of classes to provide a protected virtual void On[eventName](subclassOfEventArgs e) method to provide a way for a derived class to handle the event using an override but this class does not have it (why so restrictive?). I guess it's a poor design from Unity. This poor design also makes it hard to write unit/integration tests.
Am I missing something here? Can I still do something to trick other classes to think they are dealing with VRInput class while replaying the game?
In fact you can trigger theses events (OnClick, OnDoubleClick or any other events) from another class and without using reflection using this clever hack (Inspired by this article):
C# is not really type safe so you can share the same memory location. First declare a class with two fields that share the same memory space:
[StructLayout(LayoutKind.Explicit)]
public class OverlapEvents
{
[FieldOffset(0)]
public VRInput Source;
[FieldOffset(0)]
public EventCapture Target;
}
Then you can declare a new class that will intercept and call the other event:
public class EventCapture
{
public event Action OnClick;
public void SimulateClick()
{
InvokeClicked();
}
// This method will call the event from VRInput!
private void InvokeClicked()
{
var handler = OnClick;
if (handler != null)
handler();
}
}
Then finally register it and call it:
public static void Main()
{
input = GetComponent<VRInput>();
// Overlap the event
var o = new OverlapEvents { Source = input };
// You can now call the event! (Note how Target should be null but is of type VRInput)
o.Target.SimulateClick();
}
Here is a simple dotNetFiddle that show it working (at least outside of unity)
It is recommended for this type of classes to provide a protected virtual void On[eventName](subclassOfEventArgs e) method to provide a way for a derived class to handle the event using an override but this class does not have it (why so restrictive?). I guess it's a poor design from Unity. This poor design also makes it hard to write unit/integration tests.
All code is good code. All code is also bad code. Depends on your evaluation criteria. Unity's developers probably didn't think about your use case. As another conflicting rule of thumb, software should also be as simple & rigid as possible, so anticipating subclassing without a known use case might be considered overengineering.
As for how you can work around this, see How do I raise an event via reflection in .NET/C#?
I'm studying some examples provided by Microsoft for win8 development. I opened BasicControls sample and noticed LayoutAwarePage class and more precisely ObservableDictionary class. Reading about implementing events and raising them I can't see who's responsible to raise MapChangedEventHandler event. Based on parameters I believe that private void InvokeMapChanged(CollectionChange change, K key) method do this. But according to MSDN we need to provide a protected method that begins with On which doesn't occur in ObservableDictionary.
So, who raises MapChangedEventHandler?
An event in a class can be raised from within the class without need of an additional method to that.
So, if MapChangedEventHandler is an event, it can be called from inside the class just by this:
if (MapChangedEventHandler != null)
MapChangedEventHandler( parameters );
The only motive I can see (I'm not an expert) to the existance of those OnWhatever methods is to allow raising events from outside the class, or from some derived class, since events can only be raised from inside the declaring class.
Those OnWhatever methods must be some good practice (not a rule, nor a compiler rule).
Maybe they also take care of some additional stuff together with raising the event.
If they are not provided, probably they are not meant to be called from outside or from a derived class.
By the way, the MapChangedEventHandler is not an event. It's a delegate.
Events can be of that type, but their names are independant.
Like this:
class TestClass
{
these are the events of the class:
public event MapChangedEventHandler SomeEvent1;
public event MapChangedEventHandler SomeEvent2;
public event MapChangedEventHandler SomeEvent3;
//now this method calls the events (events can only be raised from inside the class)
public void SomeMethod()
{
//do lots of stuff
if (SomeEvent1 != null) SomeEvent1(whatever arguments it takes);
//do other stuff
if (SomeEvent2 != null) SomeEvent2(another arguments);
}
//now, if you want to let derived classes to raise events...
protected void OnSomeEvent3(Same Parameters As MapChangedEventHandler)
{
if (SomeEvent3 != null) SomeEvent3(parameters);
}
}
Say I have a class like this:
public class FauxIdentityForm
{
public Guid FormID { get; set; }
public event EventHandler Closed;
public void TheObjectWasClosed(EventArgs e)
{
Closed(this, e);
}
}
It is fine for me to call the Closed Event inside the TheObjectWasClosed method. But if, in a different class (even in the same file), I have a method like this:
public void CallTheEvent()
{
FauxIdentityForm _formIdentity = new FauxIdentityForm {FormID = Guid.NewGuid()};
_formIdentity.Closed(_formIdentity, null); // <-- Does not compile!
}
The call to Closed is shot down by the compiler (it wants me to only use += and -=).
So, is actually calling the event only allowed inside the class? Is that the limitation?
If so, is there anyway around it? And if not, why did the creators of C# do this? (It makes working with events very hard sometimes. I imagine there is a good reason and it is probably saving me from myself, but I would like to know it.)
It's complicated :)
What you're using is called a field-like event. When you declare one of those in your class, you're creating a field and an event. When you "call the event" you're actually invoking the delegate referred to by the field. As it's a private field, you have access to it within the class (and any nested types), but not outside.
Events themselves in C# only support add and remove operations. From the outside, callers can only subscribe to an event and unsubscribe from it. They can't raise it, or find out anything about who's subscribed. Of course, the class can provide a method which will raise the event, but the other class can't access the backing field for the event
I've written this up in more detail in an article about events and delegates.
In fact, Closed(this, e); is nothing but calling invoke on a private delegate. This is why only the class can call it.
C# hides all the complexity from you and it creates a private delegate of type event for you (you can use ILDASM to see all this).
This is private so it is not even protected. This is why it is recommended to use a protected method to raise the event so the subclasses could have access to the event.
So, is actually calling the event only allowed inside the class? Is that the limitation?
Yes
If so, is there anyway around it?
Only with the consent (help) from the FauxIdentityForm class. It could have a public OnClosed() method.
An Event is a lot like a property, one of its main purposes is encapsulation and that is what you ran into.
I have this class:
public class GenericEventArgs<T> : EventArgs
{
public GenericEventArgs() : this(default(T)) {}
public GenericEventArgs(T value) { Value = value; }
public T Value { get; private set; }
}
And this event handler delegate for it:
public delegate void GenericEventHandler<T>(object sender, GenericEventArgs<T> e);
I currently have these in the same file together in a namespace. Is that considered bad/messy/etc.? Cause, in general I would say that each file should contain only one class. So to have it clean I would prefer to have the GenericEventArgs class in the file alone. But then I have this GenericEventHandler<T> delegate that I am not sure where I should place. Should it have its own file? With just... that one line kind of? (and the namespace of course)
How do you usually do this?
Any reason for not using EventHandler<TEventArgs>? I thought there was an equivalent EventArgs<T> but I can't see it at the moment... Anyway, I'd put GenericEventArgs in GenericEventArgs.cs
Personally, when I want to introduce my own delegate types (which is increasingly rare, to be honest) I create a Delegates.cs file with all the appropriate delegates for the namespace in. Then I know where to find them without having a file for a single declaration.
When I wanted to create my own eventhandler delegates, I used to create one file which had the name of the EventArgs class that I used in my own eventhandler delegate.
For instance 'MyEventArgs.cs'.
That file contained the MyEventArgs class, and the MyEventHandler delegate that used this class.
Now however, I use the existing generic EventHandler (EventHandler<T>), and I only have to create my custom EventArgs class. So, this 'problem' doesn't exists anymore for me. :)
Well I'd put the GenericEventArgs<T> class in it's own file called
GenericEventArgs_T.cs in the same namespace as everything else.
And I'd put your delegate (and event if there is one) in the class that's going to have that event exposed on it.
I'd do what you are already doing and then put all delegates that are not used for events in a separate .cs file called Delegates.cs or something similar.