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.
Related
This one's a bit esoteric.
Consider the following code:
class MyObject {
public static event EventHandler SomeEvent;
}
class Container<T> {
public Container() {
T.SomeEvent += OnSomeEvent; // will not compile
}
void OnSomeEvent(object sender, object eventArgs) { }
}
Container<MyObject> foo;
Of course this will not compile, because the compiler doesn't know the type of T at compile time. More specifically, it doesn't know for certain that it has the event in question.
How do I attach an event handler to a static event SomeEvent of template parameter T? Do I need to do messy reflection?
Yes, you would need to use reflection here - and it will be messy. I would also suggest using Type instead of <T> here, as static class etc can't be used with <T>, which could limit the usage. However, as a general rule: you should actively minimize static events anyway (they're a great way to cause memory leaks, and are hard to isolate), so it might be preferable to use an alternative design altogether.
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 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
}
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.
What is considered better style for an event definition:
public event Action<object, double> OnNumberChanged;
or
public delegate void DNumberChanged(object sender, double number);
public event DNumberChanged OnNumberChanged;
The first takes less typing, but the delegate one gives names to the parameters. As I type this, I think number 2 is the winner, but I could be wrong.
Edit: A different (third) approach is the winner. Read below.
Neither 1 or 2. A third option is the winner
public event EventHandler<NumberChangedEventArgs> NumberChanged;
You're breaking a number of style guidelines for developing in C#, such as using a type for event args that doesn't extend EventArgs.
Yes, you can do it this way, as the compiler doesn't care. However, people reading your code will do a WTF.
Don't create a new type if you don't have to. I think this is better:
public event Action<object, double> OnNumberChanged;
The reason that the Action and Func delegate families exist is to serve this very purpose and reduce the need for new delegate type creation by developers.
Typically I stick to using an EventArgs derived class as the argument. It makes the code much more consistent.
I have a class:
public class ApplyClickedEventArgs : EventArgs
{
...
}
and a handler:
void cpy_ApplyClicked(object sender, ApplyClickedEventArgs e)
{
...
}
The declaration is:
public event EventHandler<ApplyClickedEventArgs> ApplyClicked;
As with all questions about coding style. Pick the one you prefer, or that your team prefers, and keep it consistent throughout the project. As long as everyone who needs to can read it efficiently you will be fine.
I think option 1 is better if I were to choose, but IIRC, the official guidelines for events state that your second parameter has to be a class with the name XxxEventArgs, and should have EventArgs up in its inheritance chain.