Click here to Skip to main content
16,020,447 members
Please Sign up or sign in to vote.
3.67/5 (2 votes)
See more:
I am trying to create a simple template of an event which adds a string parameter to an event handler, which is abstract in the sense that it is not linked to any UI control.

However, I am getting something wrong because the string assigned as a parameter is resulting in a null reference, so I am probably not creating the event handler or the delegate properly.

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication2
{
    public class Class1
    {
        public delegate void FirstHandler(string msg);
        public event FirstHandler isClassLoaded;

        public Class1()
        {
            if (this.isClassLoaded == null) { Console.WriteLine("ClassLoaded null argument"); }
            this.isClassLoaded("10 points"); 
            Console.WriteLine(isClassLoaded.ToString());
        }

        protected void FirstHandler_EventHandler(object sender, EventArgs eventargs)
        {
            
        }
      
    }
}
Posted
Comments
BillWoodruff 9-Sep-13 3:54am    
Your code suggests to me that you are not quite yet on "firm ground" in understanding Delegates and Events in .NET. I'd recommend you visit this MSDN web-page, and study the example code there in detail: http://msdn.microsoft.com/EN-US/library/vstudio/8627sbea(v=vs.100).aspx

You first need to add a handler reference to the delegate object. See the C# tutorials, especially http://msdn.microsoft.com/en-us/library/aa288459(v=vs.71).aspx[^].
 
Share this answer
 
You are not using the recommended event declaration and handling schema designed to add additional arguments to the event in a uniform way. At the same time, you are trying to handle the even as if this schema is followed; as a result, you deal with EventArgs parameters which "knows" nothing about your string parameter. This scheme is based on overriding EventArgs class, but you are trying to use the base class; no wonder you cannot pass this string parameter.

Here is what you can do:
C#
class MessageEventArgs : System.EventArgs {
    internal MessageEventArgs(string message) { this.Message = message; }
    public string Message { get; private set; } // this way, set is only used by a constuctor,
                                                // and get is needed to be public, to be accessed by the handlers
} // class MessageEventArgs

class MyClass {
   public System.EventHandler<MessageEventArgs> ClassLoaded; // instead of Systen.EventHandler
   void InvokeEvent(string message) {
       if (ClassLoaded)
           ClassLoaded.Invoke(this, new MessageEventArgs(message));
   }
} // class MyClass


By the way, the name of your event makes no sense anyway (a class is not "loaded", but it is instantiated), and it makes no sense anyway, because, if a constructor is not called, no code can add a handler to the invocation list of your even handler (it does not yet exist, unless it is static, which would make too little sense), and there is no point to handle an event in the declaring class itself. That's why I did not reproduce your constructor — the whole idea is wrong.

But, let's get back to event and its handling. The code using the class can add a handler to the invocation list of an event handler:
C#
MyClass myObject = new MyClass( /* ... */ );
//...
myObject.ClassLoaded += (sender, eventArgs) => { // now eventArgs type is MessageEventArgs, inferred by a compiler from event type
    // so, in the handler you can use Message:
    HandleTheMessageTheWayYouWant(eventArgs.Message); // the value will be passed from the moment of invocation
};


—SA
 
Share this answer
 
Comments
phil.o 8-Sep-13 17:30pm    
5! :)
Sergey Alexandrovich Kryukov 9-Sep-13 0:38am    
Thank you, Phil.
—SA
Sergey Alexandrovich Kryukov 9-Sep-13 1:20am    
However, on second thought, this is not the main OP's problem, so the real answer would be my Solution 3, please see.
—SA
Andreas Gieriet 8-Sep-13 18:50pm    
My 5!
Cheers
Andi
Sergey Alexandrovich Kryukov 9-Sep-13 0:38am    
Thank you, Andi.
—SA
I think I need to explain more why your approach is pointless. Your code is simply equivalent to this:

C#
public class Class1
{
        //public delegate void FirstHandler(string msg); // no need for this type
        //public event FirstHandler isClassLoaded;       // no need for this event instance
 
        public Class1()
        {
            if (this.isClassLoaded == null) { Console.WriteLine("ClassLoaded null argument"); }
            FirstHandler_EventHandler("10 points"); 
            Console.WriteLine(isClassLoaded.ToString());
        }
 
        protected void FirstHandler_EventHandler(string message) // pseudo-abstract, inheritance will add functionality to it
        {
            //...
        }
      
}


Are you getting the idea? The event instances are needed to handle some event by different users of the class independently. Those users add different handles to the invocation list of the event, and all those handlers are called by the method Invoke of the event instance. Handling the event in the class declaring the event is totally useless and means defeat of the purpose of events.

Another your problem is the idea that instantiation of the class object can be handled with an instance (non-static) event. Your event is public, so it implies the class still can have users which can handle the event. The problem is: this event instance will never call any handlers (except your FirstHandler_EventHandler, which is pointless as I already explained before). Why? Just because the user code will be able to add a handler to this event after the instance of the class is already obtained. But in this case, a handler would be added too late, as the event instance is only invoked in the constructor. More generally, invocation of any non-static (instance) events in a constructor is totally useless.

Also, handling such event as object creation (which you mistakenly call "loading") is useless in principle. When you have a fragment of code creating the object, this is your event. Just think about it.

And, just for a record: with static event instances, the situation is totally different. You can use similar technique to catch the event when every instance of some class is created. This may make some sense, because one part of code creates an instance, and some other parts get notification on this event. But you should understand that using any static members is not thread-safe. To make such technique thread-safe, you could use thread synchronization primitives (such as lock), but the use of them depends on the threading scenario, so I would prefer not to discuss threading here. For example:

C#
class MyClass {
   public static System.EventHandler ClassLoaded; // WARNING: not thread-safe!

   public MyClass() {}
       //...
       if (ClassLoaded != null)
          ClassLoaded.Invoke(this, new EventArgs());
   }

   //...

} // class MyClass

//...

MyClass firstObject = new MyClass();
//...
MyClass secondObject = new MyClass();
It may make certain sense because the event of creation of each of the instances (like those shown above) could be handled in one more mode different places of code:
C#
MyClass.ClassLoaded += (sender, eventArgs) => { // note that the instance is not needed because ClassLoaded is static, that's the key
   MyClass instance = (MyClass)sender; // you can be sure that this cast is successful
   instance.SomeMyClassMember // this is how you can access the created instance and its instance members
}


Are you getting the idea now?

—SA
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900