Click here to Skip to main content
15,891,607 members
Please Sign up or sign in to vote.
4.50/5 (2 votes)
See more:
Can CLI/C++ events be treated like a data member?
e.g. in the following code,
C++
public ref class MyClass
{
public:
  delegate bool delOnEnum(int h);
  event delOnEnum ^OnEnum;
  bool handler(int h)
  {
    System::Console::WriteLine("Found a new window {0}", h);
    return true;
  }
  MyClass()
  {
   if ( OnEnum ) // returns C3918, usage requires OnEnum to be data member of MyClass
    OnEnum = gcnew delOnEnum(this, &MyClass::handler);
  }
};

The error C3918 at line if (OnEnum) is generated in Visual Studio 2008 compiler. Is it correct syntax? Or there is some other means of checking if event handler has been defined.
Posted
Updated 10-Feb-11 23:34pm
v2
Comments
JF2015 11-Feb-11 5:34am    
Added code formatting.
Sergey Alexandrovich Kryukov 11-Feb-11 12:01pm    
Interesting question, my 5. Please see my answer.
--SA

Essentially events are data members. This is misleading error message specific to C++/CLI.
I saw many discussions on the, never a correct answer (so far).
It's hard to say why the check is not possible (strictly speaking, it should be if System::Object::ReferenceEquals(OnEnum, nullptr)), but you never need it!

At the moment of adding of a very first handler to an event's invocation list, the event object is nullptr, always. There is no other way of making it non-null but adding an event handler. It's OK to be null at the moment of adding first event handler; and after that event object becomes non-null.

Moreover, anyone can check up (with delegates in C#, using same very ReferenceEquals method) that at the moment of adding yet another handler to the invocation list, the delegate object looses its referential identity! Every time you add a new handler, the reference is changed, which does not prevent the delegate instance or event to work property but presents a little problem when you work with referential identity.

So, just scratch the check and be happy!

—SA
 
Share this answer
 
v4
Comments
Nish Nishant 11-Feb-11 12:15pm    
Voted 5 for the extra info provided.
Sergey Alexandrovich Kryukov 11-Feb-11 12:21pm    
Sure, thank you.
--SA
In C++/CLI you cannot directly access an event in that manner. In C# you do need to check for null and thus you need to have access to the event. But C++/CLI will generate code in the event-raise handler that will check for null.

Second issue is you cannot directly assign to the event like that. You can only subscribe to the event using +=. I've fixed your code example as follows:

MC++
public ref class MyClass
{
public:
  delegate bool delOnEnum(int h);

  event delOnEnum ^OnEnum;

  bool handler(int h)
  {
    System::Console::WriteLine("Found a new window {0}", h);
    return true;
  }

  MyClass()
  {
    OnEnum += gcnew delOnEnum(this, &MyClass::handler);
  }

  void Foo()
  {
    OnEnum(16);
  }
};
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 11-Feb-11 12:12pm    
Nishant, this is correct, my 5, but the issue (which is not an issue in fact) is somewhat deeper.
See my answer and the consideration of referential identity.
--SA
Nish Nishant 11-Feb-11 12:14pm    
I looked at your answer. I think you may be over-analyzing it. The reason a new delegate is created whenever you subscribe to a new handler is that delegates are immutable.
Sergey Alexandrovich Kryukov 11-Feb-11 12:18pm    
What do you mean "over"?
By you agree that the check is never needed?

And -- how delegates are immutable, if for every delegate you can add another handler to the invocation list, so invocation list is growing, and this is a mutation, is it not?

--SA
Nish Nishant 11-Feb-11 12:20pm    
No it's not a mutation, because when you add a new delegate, the old delegate is discarded and the new combined delegate is assigned as the event's backing delegate.

In C#, you always need to check for null. And in multi threaded scenarios you also need to make a local copy.
Sergey Alexandrovich Kryukov 11-Feb-11 23:27pm    
Oh, sure, how come I did not understand it in first place?
Thank you for clarification (which won't be needed if I thought a bit more)!
--SA
After reading all the answers, I realize that check for null handlers is not required. Actually, I had converted this code from C# to C++. The coverter did not remove this check and I was getting compiler error. But now I understand the differences across C++ & C#. Thanks for reply. All the answers have been similar. I have marked SA's reply as answer as he was first to reply. Thanks to Mr. Nishant also.
 
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