Not able to access event defined in a class - c#

I am trying to subscribe a event but it is showing error on the mentioned line. Can anyone tell me what the problem in my code is?
I am new to programming, so kindly please provide a detailed answer. Thanks in advance
namespace Events
{
delegate void MyEventHandler();
internal class ArrayListExamplePublisher : ArrayList
{
public event MyEventHandler objMyEventHandler;
void OnAdded()
{
if (objMyEventHandler != null)
{
objMyEventHandler();
}
}
public override int Add(object? value)
{
OnAdded();
return base.Add(value);
}
}
public class ArrayListExample
{
static void Main()
{
ArrayList arrayList = new ArrayList();
// Here I get an error
arrayList.objMyEventHandler += () => Console.WriteLine("Object Added");
arrayList.Add(1);
arrayList.Add("4");
}
}
}

You are adding the event to ArrayListExamplePublisher, not ArrayList, so when you try to assign that event on an ArrayList, it fails.
You can't add an event to a class externally in C# - you'd have to modify the definition of ArrayList, which you can't do.
You could do:
ArrayListExamplePublisher arrayList = new ArrayListExamplePublisher();
and set the event on that, but it's not clear if that's what you want.
Side note: The framework already has ObservableCollection<T> that has events for when the collection is modified (and is strongly-typed, unlike ArrayList.

Your lambda expression has to match the delegate type for the event.
Most events take two arguments, so this should probably work:
arrayList.objMyEventHandler += ( s, e ) => Console.WriteLine("Object Added");

So i have figured it out
As i am inheriting the class ArrayList so I should use object of child class but i was using the object of parent class. This works perfectly
ArrayListExamplePublisher objArrayListExamplePublisher = new ArrayListExamplePublisher();
objArrayListExamplePublisher.Added += () => Console.WriteLine("Object Added");
objArrayListExamplePublisher.Add(1);
objArrayListExamplePublisher.Add("4");

Related

When to use an event instead of a delegate in C#? [duplicate]

What are the differences between delegates and an events? Don't both hold references to functions that can be executed?
An Event declaration adds a layer of abstraction and protection on the delegate instance. This protection prevents clients of the delegate from resetting the delegate and its invocation list and only allows adding or removing targets from the invocation list.
To understand the differences you can look at this 2 examples
Example with Delegates (in this case, an Action - that is a kind of delegate that doesn't return a value)
public class Animal
{
public Action Run {get; set;}
public void RaiseEvent()
{
if (Run != null)
{
Run();
}
}
}
To use the delegate, you should do something like this:
Animal animal= new Animal();
animal.Run += () => Console.WriteLine("I'm running");
animal.Run += () => Console.WriteLine("I'm still running") ;
animal.RaiseEvent();
This code works well but you could have some weak spots.
For example, if I write this:
animal.Run += () => Console.WriteLine("I'm running");
animal.Run += () => Console.WriteLine("I'm still running");
animal.Run = () => Console.WriteLine("I'm sleeping") ;
with the last line of code, I have overridden the previous behaviors just with one missing + (I have used = instead of +=)
Another weak spot is that every class which uses your Animal class can invoke the delegate directly. For example, animal.Run() or animal.Run.Invoke() are valid outside the Animal class.
To avoid these weak spots you can use events in c#.
Your Animal class will change in this way:
public class ArgsSpecial : EventArgs
{
public ArgsSpecial (string val)
{
Operation=val;
}
public string Operation {get; set;}
}
public class Animal
{
// Empty delegate. In this way you are sure that value is always != null
// because no one outside of the class can change it.
public event EventHandler<ArgsSpecial> Run = delegate{}
public void RaiseEvent()
{
Run(this, new ArgsSpecial("Run faster"));
}
}
to call events
Animal animal= new Animal();
animal.Run += (sender, e) => Console.WriteLine("I'm running. My value is {0}", e.Operation);
animal.RaiseEvent();
Differences:
You aren't using a public property but a public field (using events, the compiler protects your fields from unwanted access)
Events can't be assigned directly. In this case, it won't give rise to the previous error that I have showed with overriding the behavior.
No one outside of your class can raise or invoke the event. For example, animal.Run() or animal.Run.Invoke() are invalid outside the Animal class and will produce compiler errors.
Events can be included in an interface declaration, whereas a field cannot
Notes:
EventHandler is declared as the following delegate:
public delegate void EventHandler (object sender, EventArgs e)
it takes a sender (of Object type) and event arguments. The sender is null if it comes from static methods.
This example, which uses EventHandler<ArgsSpecial>, can also be written using EventHandler instead.
Refer here for documentation about EventHandler
In addition to the syntactic and operational properties, there's also a semantical difference.
Delegates are, conceptually, function templates; that is, they express a contract a function must adhere to in order to be considered of the "type" of the delegate.
Events represent ... well, events. They are intended to alert someone when something happens and yes, they adhere to a delegate definition but they're not the same thing.
Even if they were exactly the same thing (syntactically and in the IL code) there will still remain the semantical difference. In general I prefer to have two different names for two different concepts, even if they are implemented in the same way (which doesn't mean I like to have the same code twice).
Here is another good link to refer to.
http://csharpindepth.com/Articles/Chapter2/Events.aspx
Briefly, the take away from the article - Events are encapsulation over delegates.
Quote from article:
Suppose events didn't exist as a concept in C#/.NET. How would another class subscribe to an event? Three options:
A public delegate variable
A delegate variable backed by a property
A delegate variable with AddXXXHandler and RemoveXXXHandler methods
Option 1 is clearly horrible, for all the normal reasons we abhor public variables.
Option 2 is slightly better, but allows subscribers to effectively override each other - it would be all too easy to write someInstance.MyEvent = eventHandler; which would replace any existing event handlers rather than adding a new one. In addition, you still need to write the properties.
Option 3 is basically what events give you, but with a guaranteed convention (generated by the compiler and backed by extra flags in the IL) and a "free" implementation if you're happy with the semantics that field-like events give you. Subscribing to and unsubscribing from events is encapsulated without allowing arbitrary access to the list of event handlers, and languages can make things simpler by providing syntax for both declaration and subscription.
What a great misunderstanding between events and delegates!!! A delegate specifies a TYPE (such as a class, or an interface does), whereas an event is just a kind of MEMBER (such as fields, properties, etc). And, just like any other kind of member an event also has a type. Yet, in the case of an event, the type of the event must be specified by a delegate. For instance, you CANNOT declare an event of a type defined by an interface.
Concluding, we can make the following Observation: the type of an event MUST be defined by a delegate. This is the main relation between an event and a delegate and is described in the section II.18 Defining events of ECMA-335 (CLI) Partitions I to VI:
In typical usage, the TypeSpec (if present) identifies a delegate whose signature matches the arguments passed to the event’s fire method.
However, this fact does NOT imply that an event uses a backing delegate field. In truth, an event may use a backing field of any different data structure type of your choice. If you implement an event explicitly in C#, you are free to choose the way you store the event handlers (note that event handlers are instances of the type of the event, which in turn is mandatorily a delegate type---from the previous Observation). But, you can store those event handlers (which are delegate instances) in a data structure such as a List or a Dictionary or any other else, or even in a backing delegate field. But don’t forget that it is NOT mandatory that you use a delegate field.
NOTE: If you have access to C# 5.0 Unleashed, read the "Limitations on Plain Use of Delegates" in Chapter 18 titled "Events" to understand better the differences between the two.
It always helps me to have a simple, concrete example. So here's one for the community. First I show how you can use delegates alone to do what Events do for us. Then I show how the same solution would work with an instance of EventHandler. And then I explain why we DON'T want to do what I explain in the first example. This post was inspired by an article by John Skeet.
Example 1: Using public delegate
Suppose I have a WinForms app with a single drop-down box. The drop-down is bound to an List<Person>. Where Person has properties of Id, Name, NickName, HairColor. On the main form is a custom user control that shows the properties of that person. When someone selects a person in the drop-down the labels in the user control update to show the properties of the person selected.
Here is how that works. We have three files that help us put this together:
Mediator.cs -- static class holds the delegates
Form1.cs -- main form
DetailView.cs -- user control shows all details
Here is the relevant code for each of the classes:
class Mediator
{
public delegate void PersonChangedDelegate(Person p); //delegate type definition
public static PersonChangedDelegate PersonChangedDel; //delegate instance. Detail view will "subscribe" to this.
public static void OnPersonChanged(Person p) //Form1 will call this when the drop-down changes.
{
if (PersonChangedDel != null)
{
PersonChangedDel(p);
}
}
}
Here is our user control:
public partial class DetailView : UserControl
{
public DetailView()
{
InitializeComponent();
Mediator.PersonChangedDel += DetailView_PersonChanged;
}
void DetailView_PersonChanged(Person p)
{
BindData(p);
}
public void BindData(Person p)
{
lblPersonHairColor.Text = p.HairColor;
lblPersonId.Text = p.IdPerson.ToString();
lblPersonName.Text = p.Name;
lblPersonNickName.Text = p.NickName;
}
}
Finally we have the following code in our Form1.cs. Here we are Calling OnPersonChanged, which calls any code subscribed to the delegate.
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
Mediator.OnPersonChanged((Person)comboBox1.SelectedItem); //Call the mediator's OnPersonChanged method. This will in turn call all the methods assigned (i.e. subscribed to) to the delegate -- in this case `DetailView_PersonChanged`.
}
Ok. So that's how you would get this working without using events and just using delegates. We just put a public delegate into a class -- you can make it static or a singleton, or whatever. Great.
BUT, BUT, BUT, we do not want to do what I just described above. Because public fields are bad for many, many reason. So what are our options? As John Skeet describes, here are our options:
A public delegate variable (this is what we just did above. don't do this. i just told you above why it's bad)
Put the delegate into a property with a get/set (problem here is that subscribers could override each other -- so we could subscribe a bunch of methods to the delegate and then we could accidentally say PersonChangedDel = null, wiping out all of the other subscriptions. The other problem that remains here is that since the users have access to the delegate, they can invoke the targets in the invocation list -- we don't want external users having access to when to raise our events.
A delegate variable with AddXXXHandler and RemoveXXXHandler methods
This third option is essentially what an event gives us. When we declare an EventHandler, it gives us access to a delegate -- not publicly, not as a property, but as this thing we call an event that has just add/remove accessors.
Let's see what the same program looks like, but now using an Event instead of the public delegate (I've also changed our Mediator to a singleton):
Example 2: With EventHandler instead of a public delegate
Mediator:
class Mediator
{
private static readonly Mediator _Instance = new Mediator();
private Mediator() { }
public static Mediator GetInstance()
{
return _Instance;
}
public event EventHandler<PersonChangedEventArgs> PersonChanged; //this is just a property we expose to add items to the delegate.
public void OnPersonChanged(object sender, Person p)
{
var personChangedDelegate = PersonChanged as EventHandler<PersonChangedEventArgs>;
if (personChangedDelegate != null)
{
personChangedDelegate(sender, new PersonChangedEventArgs() { Person = p });
}
}
}
Notice that if you F12 on the EventHandler, it will show you the definition is just a generic-ified delegate with the extra "sender" object:
public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);
The User Control:
public partial class DetailView : UserControl
{
public DetailView()
{
InitializeComponent();
Mediator.GetInstance().PersonChanged += DetailView_PersonChanged;
}
void DetailView_PersonChanged(object sender, PersonChangedEventArgs e)
{
BindData(e.Person);
}
public void BindData(Person p)
{
lblPersonHairColor.Text = p.HairColor;
lblPersonId.Text = p.IdPerson.ToString();
lblPersonName.Text = p.Name;
lblPersonNickName.Text = p.NickName;
}
}
Finally, here's the Form1.cs code:
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
Mediator.GetInstance().OnPersonChanged(this, (Person)comboBox1.SelectedItem);
}
Because the EventHandler wants and EventArgs as a parameter, I created this class with just a single property in it:
class PersonChangedEventArgs
{
public Person Person { get; set; }
}
Hopefully that shows you a bit about why we have events and how they are different -- but functionally the same -- as delegates.
You can also use events in interface declarations, not so for delegates.
Delegate is a type-safe function pointer. Event is an implementation of publisher-subscriber design pattern using delegate.
An event in .net is a designated combination of an Add method and a Remove method, both of which expect some particular type of delegate. Both C# and vb.net can auto-generate code for the add and remove methods which will define a delegate to hold the event subscriptions, and add/remove the passed in delegagte to/from that subscription delegate. VB.net will also auto-generate code (with the RaiseEvent statement) to invoke the subscription list if and only if it is non-empty; for some reason, C# doesn't generate the latter.
Note that while it is common to manage event subscriptions using a multicast delegate, that is not the only means of doing so. From a public perspective, a would-be event subscriber needs to know how to let an object know it wants to receive events, but it does not need to know what mechanism the publisher will use to raise the events. Note also that while whoever defined the event data structure in .net apparently thought there should be a public means of raising them, neither C# nor vb.net makes use of that feature.
To define about event in simple way:
Event is a REFERENCE to a delegate with two restrictions
Cannot be invoked directly
Cannot be assigned values directly (e.g eventObj = delegateMethod)
Above two are the weak points for delegates and it is addressed in event. Complete code sample to show the difference in fiddler is here https://dotnetfiddle.net/5iR3fB .
Toggle the comment between Event and Delegate and client code that invokes/assign values to delegate to understand the difference
Here is the inline code.
/*
This is working program in Visual Studio. It is not running in fiddler because of infinite loop in code.
This code demonstrates the difference between event and delegate
Event is an delegate reference with two restrictions for increased protection
1. Cannot be invoked directly
2. Cannot assign value to delegate reference directly
Toggle between Event vs Delegate in the code by commenting/un commenting the relevant lines
*/
public class RoomTemperatureController
{
private int _roomTemperature = 25;//Default/Starting room Temperature
private bool _isAirConditionTurnedOn = false;//Default AC is Off
private bool _isHeatTurnedOn = false;//Default Heat is Off
private bool _tempSimulator = false;
public delegate void OnRoomTemperatureChange(int roomTemperature); //OnRoomTemperatureChange is a type of Delegate (Check next line for proof)
// public OnRoomTemperatureChange WhenRoomTemperatureChange;// { get; set; }//Exposing the delegate to outside world, cannot directly expose the delegate (line above),
public event OnRoomTemperatureChange WhenRoomTemperatureChange;// { get; set; }//Exposing the delegate to outside world, cannot directly expose the delegate (line above),
public RoomTemperatureController()
{
WhenRoomTemperatureChange += InternalRoomTemperatuerHandler;
}
private void InternalRoomTemperatuerHandler(int roomTemp)
{
System.Console.WriteLine("Internal Room Temperature Handler - Mandatory to handle/ Should not be removed by external consumer of ths class: Note, if it is delegate this can be removed, if event cannot be removed");
}
//User cannot directly asign values to delegate (e.g. roomTempControllerObj.OnRoomTemperatureChange = delegateMethod (System will throw error)
public bool TurnRoomTeperatureSimulator
{
set
{
_tempSimulator = value;
if (value)
{
SimulateRoomTemperature(); //Turn on Simulator
}
}
get { return _tempSimulator; }
}
public void TurnAirCondition(bool val)
{
_isAirConditionTurnedOn = val;
_isHeatTurnedOn = !val;//Binary switch If Heat is ON - AC will turned off automatically (binary)
System.Console.WriteLine("Aircondition :" + _isAirConditionTurnedOn);
System.Console.WriteLine("Heat :" + _isHeatTurnedOn);
}
public void TurnHeat(bool val)
{
_isHeatTurnedOn = val;
_isAirConditionTurnedOn = !val;//Binary switch If Heat is ON - AC will turned off automatically (binary)
System.Console.WriteLine("Aircondition :" + _isAirConditionTurnedOn);
System.Console.WriteLine("Heat :" + _isHeatTurnedOn);
}
public async void SimulateRoomTemperature()
{
while (_tempSimulator)
{
if (_isAirConditionTurnedOn)
_roomTemperature--;//Decrease Room Temperature if AC is turned On
if (_isHeatTurnedOn)
_roomTemperature++;//Decrease Room Temperature if AC is turned On
System.Console.WriteLine("Temperature :" + _roomTemperature);
if (WhenRoomTemperatureChange != null)
WhenRoomTemperatureChange(_roomTemperature);
System.Threading.Thread.Sleep(500);//Every second Temperature changes based on AC/Heat Status
}
}
}
public class MySweetHome
{
RoomTemperatureController roomController = null;
public MySweetHome()
{
roomController = new RoomTemperatureController();
roomController.WhenRoomTemperatureChange += TurnHeatOrACBasedOnTemp;
//roomController.WhenRoomTemperatureChange = null; //Setting NULL to delegate reference is possible where as for Event it is not possible.
//roomController.WhenRoomTemperatureChange.DynamicInvoke();//Dynamic Invoke is possible for Delgate and not possible with Event
roomController.SimulateRoomTemperature();
System.Threading.Thread.Sleep(5000);
roomController.TurnAirCondition (true);
roomController.TurnRoomTeperatureSimulator = true;
}
public void TurnHeatOrACBasedOnTemp(int temp)
{
if (temp >= 30)
roomController.TurnAirCondition(true);
if (temp <= 15)
roomController.TurnHeat(true);
}
public static void Main(string []args)
{
MySweetHome home = new MySweetHome();
}
}
For people live in 2020, and want a clean answer...
Definitions:
delegate: defines a function pointer.
event: defines
(1) protected interfaces, and
(2) operations(+=, -=), and
(3) advantage: you don't need to use new keyword anymore.
Regarding the adjective protected:
// eventTest.SomeoneSay = null; // Compile Error.
// eventTest.SomeoneSay = new Say(SayHello); // Compile Error.
Also notice this section from Microsoft: https://learn.microsoft.com/en-us/dotnet/standard/events/#raising-multiple-events
Code Example:
with delegate:
public class DelegateTest
{
public delegate void Say(); // Define a pointer type "void <- ()" named "Say".
private Say say;
public DelegateTest() {
say = new Say(SayHello); // Setup the field, Say say, first.
say += new Say(SayGoodBye);
say.Invoke();
}
public void SayHello() { /* display "Hello World!" to your GUI. */ }
public void SayGoodBye() { /* display "Good bye!" to your GUI. */ }
}
with event:
public class EventTest
{
public delegate void Say();
public event Say SomeoneSay; // Use the type "Say" to define event, an
// auto-setup-everything-good field for you.
public EventTest() {
SomeoneSay += SayHello;
SomeoneSay += SayGoodBye;
SomeoneSay();
}
public void SayHello() { /* display "Hello World!" to your GUI. */ }
public void SayGoodBye() { /* display "Good bye!" to your GUI. */ }
}
Reference:
Event vs. Delegate - Explaining the important differences between the Event and Delegate patterns in C# and why they're useful.: https://dzone.com/articles/event-vs-delegate

Missing object Reference in redefined list using concerning extended items

He everybody,
I'm trying to setup a project management class.
In order to see if somthing in the data changed i want to implement events on the lower level of the programming structure. I have some Classes extending the ProjectComponent Class. The base class has an event and event throwing methode, which the childcomponents can use.
Now I have a couple of custom list (nameley eList) in the project object.
Because all the child component have a common parent, ProjectComponent, i would like my custom list object (eList) to subscribe to the event when an object is added and unsubscribe when removed.
However when trying to prog this, i received the following error:
'ProjectComponent' does not contain a
definition for 'itemChanged' and no
extension method 'itemChanged'
accepting a first argument of type
'ProjectComponent'
Which is kind of wierd seeing as the class clearly has that public field.
Here is a the code:
public class ProjectComponent
{
public event ItemChanged itemChanged;
public void throwItemChangedEvent(ItemChangedEventArgs Arguments)
{
if (itemChanged != null)
itemChanged(new Object(), Arguments);
}
}
public class eList<ProjectComponent> : IList<ProjectComponent>
{
List<ProjectComponent> internalList = new List<ProjectComponent>();
public override void Add(ProjectComponent Item)
{
this.internalList.Add(Item);
Item.itemChanged += new ItemChanged(ItemChanged_Handler);
}
private void ItemChanged_Handler(object sender, ItemChangedEventArgs eventArgs)
{
//do stuff here
}
}
An example how it would be called is:
public eList<ChildClass> Children = new eList<ChildClass>();
The idea is that when an object in the list is edited the list object recieve an object like so:
Children.childstring = "anything";
At the moment the field inside the Children object is changed an event could be recieved.
My question is simply what am i doing wrong, why cant i suscribe to the ProjectComponent event inside the eList class?
Or does anyone know a better way to achive the same results?
Thanks in Advance,
Harry
Edit: Definition of ItemChanged delagate:
public delegate void ItemChanged(object sender, ItemChangedEventArgs eventArgs);
public class ItemChangedEventArgs : EventArgs
{
private String p_CallStack;
public String CallStack
{
get { return this.p_CallStack; }
set { this.p_CallStack = value; }
}
public ItemChangedEventArgs()
{
p_CallStack = "";
}
public ItemChangedEventArgs(String StackStart)
{
p_CallStack = StackStart;
}
}
you have 2 errors:
1.
in generic class definition you must use variables not existing classes:
public class eList<ProjectComponent>: ...
--> public class eList<T>: ...
in your case you want to do:
public class eList : IList<ProjectComponent>
2.
Item.itemChanged += new Item.itemChanged(ItemChanged_Handler);
new Item.itemChanged has no meaning, you have to use the underlying delegate type of your event:
Item.itemChanged += new ItemChanged(ItemChanged_Handler);
N.B:
your code does not respect at all design guidelines for c#
More informations here:Naming Guidelines
Shouldn't it be
Item.itemChanged += new ItemChanged(ItemChanged_Handler);

In C# why can't I pass another class' EventHandler reference and how can I get around it?

If I have ClassA that has a public event, SomeEvent, and ClassC that has method, addListener, that accepts an EventHandler reference, why can't ClassB have a line that says c.addListener(ref a.SomeEvent)? If I try I get a compiler error that says: "The event 'ClassA.SomeEvent' can only appear on the left hand side of += or -= (except when used from within the type 'ClassA').
Why does this restriction exist? And how can I get around it while staying reasonably close to my structure?
I'm a C# newbie; any help would be appreciated. Thanks!
class ClassA {
public event EventHandler SomeEvent;
}
ClassB{
public ClassB() {
ClassA a = new ClassA();
ClassC c = new ClassC();
c.addListener(ref a.SomeEvent); //Compile error
}
}
class ClassC {
public void addListener(ref EventHandler handler) {
handler += onEvent;
}
private void onEvent(object sender, EventArgs e) {
//do stuff
}
}
Outside of the class, you only have access to the add and remove accessors - that is the point of an event you can neither see other subscribers, nor change them (for example, setting the event to null). It would be better to handle the event normally, and cause whatever consequences you need.
Imagine you could do what you suggest. For example, suppose you subscribe to a button click, and some other code uses that info to hook you into a "tick" event - you're code isn't going to work as it expected to = bug.
To make that explict; an event isn't an EventHandler, in the same way that a property isn't an int - the event/property defines accessor methods.
Re your scenario, either make OnEvent public and use a.SomeEvent += c.OnEvent;, or have some similar method and use an anon-method:
a.SomeEvent += delegate { c.DoSomethingCool(); };
The event keyword creates an accessor for a private delegate object. The exact same thing a property does, it restricts access to a private field. Your code snippet fails with a similar kind of error when you use a property instead of an event:
class ClassA {
public int Property { get; set; }
}
class ClassB {
public ClassB() {
ClassA a = new ClassA();
ClassC c = new ClassC();
c.setValue(ref a.Property); // CS0206
}
}
class ClassC {
public void setValue(ref int value) {
value = 42;
}
}
It is easier to see now, there is no way for the compiler to ensure that the setValue() method uses the property setter. Nor could it know that the "value" argument is a property with a setter or a plain field.
It is less clear for an event because there is so much syntax sugar at work. This declaration
public event EventHandler SomeEvent;
actually generates this code:
private EventHandler _SomeEvent;
public event SomeEvent {
add { _SomeEvent += new EventHandler(value); }
remove { _SomeEvent -= new EventHandler(value); }
}
The add and remove accessors are equivalent to the get and set accessors of a property, they prevent code from messing with the private _SomeEvent field. By convention, the add accessor is invoked when you use +=, remove is invoked with -=. Compare this with the earlier example I gave for a property. Same problem, you can't use the ref keyword and ClassC.addListener() would have no way to know that the handler is actually an event instead of a delegate object. If the compiler would pass _SomeEvent instead, the point of using the accessors is lost.
You can restructure the code to solve this problem:
class ClassC {
public EventHandler getListener() {
return new EventHandler(onEvent);
}
private void onEvent(object sender, EventArgs e) { }
}
...
a.SomeEvent += c.getListener();
One final note: the symmetry between an event and a property is a bit lost, the C# compiler automatically generates the add/remove accessors if you don't write them explicitly. It doesn't do this for a property. It would have made automatic properties a lot easier:
property int Property;
But that would have required adding a new keyword to the language, something the C# team really dislikes. Other languages like VB.NET and C++/CLI do have that keyword.
How can I get around it while staying reasonably close to my structure?
Use a.SomeEvent += handler instead.
Why does this restriction exist?
See Marc Gravell's answer.

How can I pass an event to a function in C#?

I am looking to pass an event to a helper function. This function will attach a method to the event. However, I am having trouble properly passing the event. I have tried passing a EventHandler<TEventArgs>. It compiles, but events are not attached (but are still added; it seems a copy of the event handler is made).
For example, if I have this:
public event EventHandler<EventArgs> MyEvent;
And the helper function:
public static void MyHelperFunction<TEventArgs>(EventHandler<TEventArgs> eventToAttachTo)
{
eventToAttachTo += (sender, e) => { Console.WriteLine("Hello world"); };
}
And the caller:
MyHelperFunction(MyEvent);
MyEvent(null, new EventArgs()); // Does nothing.
The reason why this does not work is += when applied to a delegate creates a new delegate which is the combination of the old and the new. It does not modify the existing delegate.
In order to get this to work you will have to pass the delegate by reference.
public static void Helper(ref EventHandler<EventArgs> e)
{
e+= (x,y) => {};
}
The reason this works outside of the method is because the LHS is still the actual field. So += will create a new delegate and assign back to the member field.
Just came up with this little helper. If it is your self-created Event you could use a wrapper like this. You can use your += operators to attach handlers as normal but can pass the wrapper around and even raise the event from elsewhere.
public class GenericEvent<T> where T:EventArgs
{
public event EventHandler<T> Source = delegate { };
public void Raise(object sender, T arg = default(T))
{
Source(sender, arg);
}
public void Raise(T arg = default(T))
{
Source(this, arg);
}
public void AddHandler(EventHandler<T> handler)
{
Source += handler;
}
public void RemoveHandler(EventHandler<T> handler)
{
Source -= handler;
}
public static GenericEvent<T> operator +(GenericEvent<T> genericEvent, EventHandler<T> handler)
{
genericEvent.AddHandler(handler);
return genericEvent;
}
}
Create the event like:
public GenericEvent<EventArgs> MyEvent = new GenericEvent<EventArgs>();
Attach handlers:
MyEvent += (s,e) => {};
Raise event:
MyEvent.Raise();
Just guessing: Have you tried passing it as ref?
public static void MyHelperFunction<TEventArgs>(ref EventHandler<TEventArgs> eventToAttachTo)
MyHelperFunction(ref MyEvent);
It's not exactly nice, but you can use reflection to do this.
public EventMonitor(object eventObject, string eventName)
{
_eventObject = eventObject;
_waitEvent = eventObject.GetType().GetEvent(eventName);
_handler = new EventHandler(SetEvent);
_waitEvent.AddEventHandler(eventObject, _handler);
}
Where eventObject is the object containing the event, and eventName is the name of the event.
SetEvent is your event handler.
I also have a dispose method like this:
public void Dispose()
{
_waitEvent.RemoveEventHandler(_eventObject, _handler);
}
I have a solution where I have an two interfaces. The first interface has methods for binding certain events, while the other interface has event methods that can be bound to those events.
The first interface's bind methods takes the second interface as parameter, which makes it possible to bind the events to the event methods of any class that implements the second interface.
Is that understandable, or would you prefer some code? :)
As many have pointed out, passing an event to a method is either not possible or not simple.
Please clarify, but I suspect your intended usage will look something like:
void Register()
{
var super = new SuperHandler();
//not valid syntax:
super.HandleEvent(MyEvent1);
super.HandleEvent(MyEvent2);
super.HandleEvent(MyEvent3);
super.HandleEvent(MyEvent4);
}
You can accomplish this simply by making your intended generic event handlers accessible publicly (or internally, if you desire):
public static class GenericHandler
{
public static void HandleAnyEvent(object sender, EventArgs e)
{
//handle
}
}
public class SomeClass
{
void RegisterEvents()
{
var r = new EventRaiser();
r.ImportantThingHappened += GenericHandler.HandleAnyEvent;
}
}
In this example my catch-all handler is in a static class, but you can just as well use a non-static class. Also, I see that in your example you have made the method generic (TEventArgs). Because all EventHandler derivatives (such as CancelEventHandler) match the base EventHandler, you do not need to involve generics (nor would it be helpful).
If the registration logic is complex or you must keep the EventHandler private, consider using Interface Events. This may not meet your intended goal of reducing the amount of code, but it will allow you to create a class that can predictably handle all of the events of a specific type.
interface IRaiseEvents
{
event EventHandler ConnectionCreated;
event EventHandler ConnectionLost;
}
public class SuperHandler
{
void RegisterEvents(IRaiseEvents raiser)
{
raiser.ConnectionCreated += (sender, args) => Console.WriteLine("Connected.");
raiser.ConnectionLost += (sender, args) => Console.WriteLine("Disconnected.");
}
}
Pass something like Action e = e => myevent += e;
And call from method with the handler? It has the benefit of working with .NET classes.

How to ensure an event is only subscribed to once

I would like to ensure that I only subscribe once in a particular class for an event on an instance.
For example I would like to be able to do the following:
if (*not already subscribed*)
{
member.Event += new MemeberClass.Delegate(handler);
}
How would I go about implementing such a guard?
I'm adding this in all the duplicate questions, just for the record. This pattern worked for me:
myClass.MyEvent -= MyHandler;
myClass.MyEvent += MyHandler;
Note that doing this every time you register your handler will ensure that your handler is registered only once.
If you are talking about an event on a class that you have access to the source for then you could place the guard in the event definition.
private bool _eventHasSubscribers = false;
private EventHandler<MyDelegateType> _myEvent;
public event EventHandler<MyDelegateType> MyEvent
{
add
{
if (_myEvent == null)
{
_myEvent += value;
}
}
remove
{
_myEvent -= value;
}
}
That would ensure that only one subscriber can subscribe to the event on this instance of the class that provides the event.
EDIT please see comments about why the above code is a bad idea and not thread safe.
If your problem is that a single instance of the client is subscribing more than once (and you need multiple subscribers) then the client code is going to need to handle that. So replace
not already subscribed
with a bool member of the client class that gets set when you subscribe for the event the first time.
Edit (after accepted): Based on the comment from #Glen T (the submitter of the question) the code for the accepted solution he went with is in the client class:
if (alreadySubscribedFlag)
{
member.Event += new MemeberClass.Delegate(handler);
}
Where alreadySubscribedFlag is a member variable in the client class that tracks first subscription to the specific event.
People looking at the first code snippet here, please take note of #Rune's comment - it is not a good idea to change the behavior of subscribing to an event in a non-obvious way.
EDIT 31/7/2009: Please see comments from #Sam Saffron. As I already stated and Sam agrees the first method presented here is not a sensible way to modify the behavior of the event subscription. The consumers of the class need to know about its internal implementation to understand its behavior. Not very nice.
#Sam Saffron also comments about thread safety. I'm assuming that he is referring to the possible race condition where two subscribers (close to) simultaneously attempt to subscribe and they may both end up subscribing. A lock could be used to improve this. If you are planning to change the way event subscription works then I advise that you read about how to make the subscription add/remove properties thread safe.
As others have shown, you can override the add/remove properties of the event. Alternatively, you may want to ditch the event and simply have the class take a delegate as an argument in its constructor (or some other method), and instead of firing the event, call the supplied delegate.
Events imply that anyone can subscribe to them, whereas a delegate is one method you can pass to the class. Will probably be less surprising to the user of your library then, if you only use events when you actually want the one-to-many semantics it usually offers.
You can use Postsharper to write one attribute just once and use it on normal Events. Reuse the code. Code sample is given below.
[Serializable]
public class PreventEventHookedTwiceAttribute: EventInterceptionAspect
{
private readonly object _lockObject = new object();
readonly List<Delegate> _delegates = new List<Delegate>();
public override void OnAddHandler(EventInterceptionArgs args)
{
lock(_lockObject)
{
if(!_delegates.Contains(args.Handler))
{
_delegates.Add(args.Handler);
args.ProceedAddHandler();
}
}
}
public override void OnRemoveHandler(EventInterceptionArgs args)
{
lock(_lockObject)
{
if(_delegates.Contains(args.Handler))
{
_delegates.Remove(args.Handler);
args.ProceedRemoveHandler();
}
}
}
}
Just use it like this.
[PreventEventHookedTwice]
public static event Action<string> GoodEvent;
For details, look at Implement Postsharp EventInterceptionAspect to prevent an event Handler hooked twice
You would either need to store a separate flag indicating whether or not you'd subscribed or, if you have control over MemberClass, provide implementations of the add and remove methods for the event:
class MemberClass
{
private EventHandler _event;
public event EventHandler Event
{
add
{
if( /* handler not already added */ )
{
_event+= value;
}
}
remove
{
_event-= value;
}
}
}
To decide whether or not the handler has been added you'll need to compare the Delegates returned from GetInvocationList() on both _event and value.
I know this is an old Question, but the current Answers didn't work for me.
Looking at C# pattern to prevent an event handler hooked twice (labelled as a duplicate of this question), gives Answers that are closer, but still didn't work, possibly because of multi-threading causing the new event object to be different or maybe because I was using a custom event class. I ended up with a similar solution to the accepted Answer to the above Question.
private EventHandler<bar> foo;
public event EventHandler<bar> Foo
{
add
{
if (foo == null ||
!foo.GetInvocationList().Select(il => il.Method).Contains(value.Method))
{
foo += value;
}
}
remove
{
if (foo != null)
{
EventHandler<bar> eventMethod = (EventHandler<bar>)foo .GetInvocationList().FirstOrDefault(il => il.Method == value.Method);
if (eventMethod != null)
{
foo -= eventMethod;
}
}
}
}
With this, you'll also have to fire your event with foo.Invoke(...) instead of Foo.Invoke(...). You'll also need to include System.Linq, if you aren't already using it.
This solution isn't exactly pretty, but it works.
I did this recently and I'll just drop it here so it stays:
private bool subscribed;
if(!subscribed)
{
myClass.MyEvent += MyHandler;
subscribed = true;
}
private void MyHandler()
{
// Do stuff
myClass.MyEvent -= MyHandler;
subscribed = false;
}
Invoke only distinct elements from GetInvocationList while raising:
using System.Linq;
....
public event HandlerType SomeEvent;
....
//Raising code
foreach (HandlerType d in (SomeEvent?.GetInvocationList().Distinct() ?? Enumerable.Empty<Delegate>()).ToArray())
d.Invoke(sender, arg);
Example unit test:
class CA
{
public CA()
{ }
public void Inc()
=> count++;
public int count;
}
[TestMethod]
public void TestDistinctDelegates()
{
var a = new CA();
Action d0 = () => a.Inc();
var d = d0;
d += () => a.Inc();
d += d0;
d.Invoke();
Assert.AreEqual(3, a.count);
var l = d.GetInvocationList();
Assert.AreEqual(3, l.Length);
var distinct = l.Distinct().ToArray();
Assert.AreEqual(2, distinct.Length);
foreach (Action di in distinct)
di.Invoke();
Assert.AreEqual(3 + distinct.Length, a.count);
}
[TestMethod]
public void TestDistinctDelegates2()
{
var a = new CA();
Action d = a.Inc;
d += a.Inc;
d.Invoke();
Assert.AreEqual(2, a.count);
var distinct = d.GetInvocationList().Distinct().ToArray();
Assert.AreEqual(1, distinct.Length);
foreach (Action di in distinct)
di.Invoke();
Assert.AreEqual(3, a.count);
}

Categories

Resources