12

I was wondering about the EventInfo.GetRaiseMethod and EventInfo.GetOtherMethods methods. Apparently, the CLR supports 4 kinds of methods associated with events: add, remove, raise, and "others". But events created in C# only have add and remove... I assumed that raise was used in VB, since you have to specify a RaiseEvent method when you declare a custom event, but apparently it's not the case: GetRaiseMethod always returns null.

So, does anyone know:

  • what's the point in having a raise method associated with an event if it's never used? Is there a specific MSIL instruction to raise an event using this method? (I couln't find anything like it in the opcodes)
  • what are the "other" methods returned (well, not returned actually) by GetOtherMethods? What's are they supposed to do?
  • are there types in the BCL that implement those special methods?
Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758
  • *"Is there a specific MSIL instruction to raise an event using this method?"* Nope. Just like there's no CIL instruction to set a property, get a property, add a handler, or remove a handler. They are all done with call/callvirt. (And yes, it's call CIL, not MSIL.) – cdhowie Dec 24 '10 at 00:47
  • 2
    Well, it *was* called MSIL, but it's now called CIL... I have to get used to that ;) – Thomas Levesque Dec 24 '10 at 00:51
  • This question confused me in the past, and at last I thought it's used for VB, you have tried that it still returns null in VB? – Cheng Chen Dec 24 '10 at 03:06
  • @Danny, yes, it also returns null for events created in VB (custom events and normal field-like events) – Thomas Levesque Dec 24 '10 at 08:34

2 Answers2

7

As far as I know, raise isn't used much, and I've practically never seen it used. C++/CLI is pretty much the only language I know that make it easy to declare a raise method. See this code for example:

using namespace System;

ref class Foo {

private:
    Action ^bar;

public:
    event Action ^Bar {
        void add (Action ^action)
        {
            Console::WriteLine ("add");
            bar += action;
        }

        void remove (Action ^action)
        {
            Console::WriteLine ("remove");
            bar -= action;
        }

        void raise ()
        {
            Console::WriteLine ("raise");

            if (!bar)
                return;

            Console::WriteLine ("raise for real");
            bar->Invoke ();
        }
    };
};

void hello ()
{
    Console::WriteLine ("hello");
}

void main ()
{
    Foo ^foo = gcnew Foo ();
    foo->Bar ();

    foo->Bar += gcnew Action (&hello);

    foo->Bar ();
}

Which, when being run, naturally outputs:

C:\tmp>test
raise
add
raise
raise for real
hello

To answer your question, there's no opcode to invoke an event, the compiler will just emit a call to the raise method:

  IL_0020:  ldloc.0
  IL_0021:  call       instance void Foo::raise_Bar()

Just like it emits a call to add_Bar.

It's also worth nothing that as C# allows you to invoke an event exclusively in the scope of the type which declares the member event, you can't get C# code to call that raise method. So no, you won't find such a method exposed in the BCL.

As for the .other kind of methods, I've never seen any attached to an event. And I only saw them used once for properties, and neither the book «Inside IL assembler» nor «The CLI annotated standard» give any information about them. But basically, they allow you to attach methods to a property or to a event to bind them semantically. They're neither a addon, nor a removeon, nor a raise method, but they would be part of the event, should a language need to express that. In the meantime, the only way to emit one is to use ilasm.

Community
  • 1
  • 1
Jb Evain
  • 17,319
  • 2
  • 67
  • 67
  • Thanks, very interesting answer! Perhaps if you declare a "foo" method in the event, it will appear in .other methods? – Thomas Levesque Dec 24 '10 at 09:06
  • No it won't, in Cpp/CLI, only add, remove, and raise methods are allowed. – Jb Evain Dec 24 '10 at 09:09
  • 1
    The only place I've ever seen .other implemented in an IL sample (not real code) is in Serge Lidin's book (Expert .Net 2.0 IL Assembler) which starts on page 318. The method he uses with the .other is called HasSubscribers and returns a bool. The sample IL that uses the event doesn't show any usage of the .other method though but wouldn't be too hard to put together. The thing is, with IL those are just other methods that are associated with an .event ... like with the .fire method - c# and vb don't define the .fire method for the events. (they don't associate that method with the event) – Jason Haley Dec 31 '10 at 02:39
1

Yes, C# can use the add/remove overloads for registering event handlers. EventInfo is the System.Reflection metadata that is used when parsing a class' signature; the RaiseEvent method in Visual Basic is not necessarily the same method as this one, as reflection creates a way for you to dynamically invoke an event or add an event handler. RaiseEvent is similar to calling the event in C# like a method.

(This is a partial answer, as there are questions in your post I don't know the answer too.)

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Brian Mains
  • 50,520
  • 35
  • 148
  • 257