What is the C# equivalent of the following line of VB.NET code?
Public Event TestEvent()
Public Event TestEvent() creates an event without parameters in VB.Net.
Since you cannot simple use
public event void TestEvent;
in C#, you either have to create a new delegate
public delegate void TestEventEventHandler();
public event TestEventEventHandler TestEvent;
or simply use Action, which encapsulates a method without return value and without parameters.
public event Action TestEvent;
public event System.EventHandler testEvent;
Related
I am trying to invoke an event in the interface in which it is defined (see code below).
However, I get the following error:
Program.cs(7,3): error CS0079: The event 'IMyInterface.MyEvent' can only appear on the left hand side of += or -=.
I suspect it might have something to do with all events declared in interfaces are always properties.
Is this a bug, a feature, and are there any workarounds?
Thanks.
using System;
public interface IMyInterface
{
event EventHandler? MyEvent;
void CallMyEvent()
{
MyEvent?.Invoke(this, EventArgs.Empty);
}
}
public class MyClass : IMyInterface
{
public event EventHandler? MyEvent;
}
static class Program
{
static void Main()
{
var obj = new MyClass();
obj.CallMyEvent();
}
}
I think it's because event EventHandler? MyEvent not implemented inside your interface, it will be implemented inside your class and after it, you can Invoke it:
public class MyClass : IMyInterface
{
public event EventHandler? MyEvent;
public void CallMyEvent()
{
MyEvent?.Invoke(this, EventArgs.Empty);
}
}
After C# 8 you actualy can do default implementation of methods inside interface, but only methods, not events.
If you want predefined method, that will call event, you can make abstract class instead of interface.
It appears that the only way around this problem is to invoke the event outside the interface. Either use an abstract class that I was trying to avoid, or have a regular interface method and give up DRY code.
In my product I need process wide events. For that I used code like this:
public class Global
{
public static event EventHandler<MyEventArgs> Message;
public static void ShowMessage();
}
Now let's say I have a WinForms user interface. In form's code I will subscribe to this event and handle it in some default way (eg. by using System.Windows.Forms.MessageBox.Show() method). Now the question is how do I allow user to create derived form and override my default Message event handler implementation?
Just subscribing to the event for the second time with custom implementation doesn't solve the problem (both event handlers would be executed and potentially two message boxes shown). The options I see are either:
//call OnSubscribeToMessageEvent() from either form's constructor or OnLoad event handler
protected virtual void OnSubscribeToMessageEvent()
{
Global.Message += new EventHandler<MyEventArgs>(Global_Message);
}
private void Global_Message(object sender, MyEventArgs e)
{
//my default implementation
}
or
//subscribe in either form's constructor or OnLoad event handler
protected virtual void Global_Message(object sender, MyEventArgs e)
{
//my default implementation
}
Which version is better and why? Or maybe there are any other options?
I still have some doubts as I have never seen such a design pattern in any .NET library
Yes, you're right to worry about this. These kind of event subscriptions are very fickle, the event source always outlives the subscriber. There's only one class in the framework I know that does this, SystemEvents. The problem is that every subscriber has to very carefully unsubscribe itself when its lifetime ends or the object will stay referenced forever. A memory leak that's very hard to diagnose.
A better pattern here is to use an interface. Let's declare one:
public class MyEventArgs { /* etc.. */ }
public interface IGlobalNotification {
event EventHandler Disposed;
void OnMessage(MyEventArgs arg);
}
Now you can have a form implement the interface:
public partial class Form1 : Form, IGlobalNotification {
public Form1() {
InitializeComponent();
GlobalMessages.Register(this);
}
void IGlobalNotification.OnMessage(MyEventArgs arg) {
// do something
}
}
The Register method registers the form with the GlobalMessages class, the Dispose event ensures that the class can detect that the form is dying:
public static class GlobalMessages {
public static void Register(IGlobalNotification listener) {
listener.Disposed += delegate { listeners.Remove(listener); };
listeners.Add(listener);
}
public static void Notify(MyEventArgs arg) {
foreach (var listener in listeners) listener.OnMessage(arg);
}
private static List<IGlobalNotification> listeners = new List<IGlobalNotification>();
}
Call GlobalMessages.Notify() to get the OnMessage() method to run in all live form instances. The major advantage of this approach is that a client programmer can never screw up.
I would let the derived class override the Global_Message. The subscription to the event is generic and why would you want to implement it in every child again? It also gives you the option to call base.Global_Message(sender, e) in case your child class just wants to add some decoration to it and use the default behaviour otherwise.
I would prefer your second example, as that way, classes that extend your base class only have to override one method and do not have to remove the handler added by the base class from the event.
The key is adding the virtual keyword, so that a derived type can overide the method and the method they created will be called instead.
//subscribe in either form's constructor or OnLoad event handler
protected virtual void Global_Message(object sender, MyEventArgs e)
{
//my default implementation
}
Now that you've added virtual to both, I'd go with the first and override the one that subscribes to the event, if they didn't want the event subscribed to.
Though there is another option, call it #3.
protected EventHandler GlobalMessageEvent = new EventHandler<MyEventArgs>(Global_Message);
protected virtual void OnSubscribeToMessageEvent()
{
// this could be done in the Form_Load() or constructor instead.
Global.Message += GlobalMessageEvent;
}
Then potentially an inherited class could do somewhere: (note the -=)
{
Global.Message -= GlobalMessageEvent;
}
From MSDN:
Any method that matches the delegate's
signature, which consists of the
return type and parameters, can be
assigned to the delegate.
So how is this possible:
public delegate void AlarmEventHandler(object sender, EventArgs e);
public event AlarmEventHandler Alarm;
protected virtual void OnAlarm(EventArgs e)
{
AlarmEventHandler handler = Alarm;
if (handler != null)
{
// Invokes the delegates.
handler(this, e);
}
}
delegate AlarmEventHander and event AlarmEventHandler have different signatures yet handler can be assigned to Alarm.
Perhaps I'm mis-understanding delegates somewhat, and I would be very grateful if someone could explain where I'm going wrong.
A delegate is like a class. An event is like a property. When you declare an event in a class, you declare the type of event it is. In this case, AlarmEventHandler, which is an inner class of the top-level class this is a part of.
In the OnAlarm method, you get the instance of the AlarmEventHandler class that has been assigned to the event, and invoke it.
To clear things up, your code above is similar to this, using normal classes & references:
public class InnerClass {
public void MyMethod() { /* ... */ }
}
public InnerClass MyProperty { get; set; }
protected virtual void CallMyMethod() {
InnerClass cls = MyProperty;
if (cls != null)
cls.MyMethod();
}
Actually the signatures are the same. In .NET events are implemented with delegates.
public event AlarmEventHandler Alarm;
So above code is actually compiled by compiler as:
private AlarmEventHandler handler;
public event AlarmEventHandler Alarm
{
add { handler += value; }
remove { handler -= value; }
}
So event actually uses the same AlarmEventHandler delegate.
You are mixing delegates and events. While events are dependant on delegates, they are difference concepts completly. So should be taken separately.
Delegate is like type definition. Place where you use this delegate is like variable or property.
Event makes this delegate behave differently from the outside. Signature is still same.
An event is just a delegate. The delegate itselft can only be accessed from inside the class.
From the outside, only add and remove functionality for the event is possible to you can only do this:
myAlarm.Alarm+=new AlarmEventHandler(callPolice);
// or
myAlarm.Alarm-=new AlarmEventHandler(callPolice);
But from the inside of the class, Alarm is just a delegate of type AlarmEventHandler so you can do what your code shows:
AlarmEventHandler handler = Alarm;
if (handler != null)
{
// Invokes the delegates.
handler(this, e);
}
A function which takes a base-class as (non reference) parameter can be converted to a delegate that takes a derived class as parameter. This is because the function that takes base can be safely substituted where-ever a function that takes a derived class is used.
void TakesObject(object o)
{
...
}
Action<string> myAction=TakesObject;
You can call myAction only by passing in a string. And since every string is an object the contract for TakesObject is fulfilled.
In your case is works because every AlarmEventArgs is an EventArgs too. So the contract requirements of your eventhandler are less strict than the contract guarantees of the delegate type used by the event.
This is called co- and contra-variance. You have co-variance in return-types, and contra variance in parameters.
Check this article on MSDN:
Using Variance in Delegates (C# and Visual Basic)
In my class I want to declare an event that other classes can subscribe to. What is the correct way to declare the event?
This doesn't work:
public event CollectMapsReportingComplete;
You forgot to mention the type. For really simple events, EventHandler might be enough:
public event EventHandler CollectMapsReportingComplete;
Sometimes you will want to declare your own delegate type to be used for your events, allowing you to use a custom type for the EventArgs parameter (see Adam Robinson's comment):
public delegate void CollectEventHandler(object source, MapEventArgs args);
public class MapEventArgs : EventArgs
{
public IEnumerable<Map> Maps { get; set; }
}
You can also use the generic EventHandler type instead of declaring your own types:
public event EventHandler<MapEventArgs> CollectMapsReportingComplete;
You need to specify the delegate type the event:
public event Action CollectMapsReportingComplete;
Here I have used System.Action but you can use any delegate type you wish (even a custom delegate). An instance of the delegate type you specify will be used as the backing field for the event.
An Example
/// </summary>
/// Event triggered when a search is entered in any <see cref="SearchPanel"/>
/// </summary>
public event EventHandler<string> SearchEntered
{
add { searchevent += value; }
remove { searchevent -= value; }
}
private event EventHandler<string> searchevent;
public event EventHandler MyEvent;
public event [DelegateType] [EventName];
I had once a situation where I had to override the event handler in some derived class of mine. I could not unfortunately just "override" it since the implementation logic was bound strictly to that particular method implementation in the base class.
My natural idea was to first "unbind" the original event handler from the event and then to bind my own brand-new method. So I tried to use the "-=" operator like:
myObject.SomeEvent -= new EventHandler (BaseClass.SomeEventHandler)
at which point the compiler complainer that it had no access to the private method SomeEventHandler. Since the base class was a part of the library I did not really want to modify its implementation (though simply as it seems by just turning "private" into "protected");
It's so simple to attach an event handler to an event. Why is it so difficult to get rid of one?
Why I wanted it? Because the base implementation was casing some problems (just did not handle our particular case) so I wanted to redefine it. But even after I attached my event handler the base implementation was getting executed anyway. Since it was doing some kind of Redirect, my own implementation was never going to run since the request processing was being broken at server after redirect.
Is there anyway to get rid of an event handler in a base class from a library without modifying its implementation?
It would be just as easy to get rid of the handler if your code can officially see the handler. If absolutely necessary, it is possible to unsubscribe using reflection to get hold of the delegate, but this is messy. It would be a lot cleaner and safer to either a: avoid the requirement, or b: change the code to make the handler protected.
Reflection approach (use at own risk); uncomment the block in the Bar.ctor() to see the change.
using System;
class Foo
{
public event EventHandler SomeEvent;
public Foo()
{
SomeEvent += SecretHandler; // a bad idea, anyway
//(self-subscribed events....)
}
protected virtual void OnSomeEvent()
{
EventHandler handler = SomeEvent;
if (handler != null) handler(this, EventArgs.Empty);
}
private void SecretHandler(object sender, EventArgs args)
{
Console.WriteLine("suscribed");
}
}
class Bar : Foo
{
public Bar()
{
/*
MethodInfo method = typeof(Foo).GetMethod("SecretHandler",
BindingFlags.NonPublic | BindingFlags.Instance);
EventHandler handler = (EventHandler)Delegate.CreateDelegate(
typeof(EventHandler), this, method);
SomeEvent -= handler;
*/
}
public void Test()
{
OnSomeEvent();
}
}
static class Program
{
static void Main()
{
Bar bar = new Bar();
bar.Test();
}
}