Delegates are useful, and here is why (sample program)

R

raylopez99

Regarding delegates used as events in the .NET framework--I've
discovered (for me) a shocking non-standard way that events are fired
when using the System.EventArgs class, which apparently is manditory,
as is the "On" prefix for any member function that uses an "EventArgs"
type delegate. While I don't have time to discuss the "On" prefix in
this thread, suffice it to say that Eventhandler delegates used in a
class can (it's complicated) use a protected virtual method that fires
the event but must have prefix "On" as the name of the method. But
you can define a so-called non-generic EventHandler delegate that
avoids this, at the penalty of not conveying information back to any
class that is derived from EventArgs class. Source: C#3.0 Nutshell
by Albahari. It's really convoluted. They give an example but you
have to study it for like an hour, and like yoga, it finally comes to
you by osmosis. Also they show a cool way of using 'get' and 'set' to
fire an event, but that's kinda just eye candy.

But, I also discovered a shorthand way that delegates are chained, see
below. It's confusing when you first see this, so I am warning
newbies like myself.

Note these below lines are IDENTICAL!!!

this.buildProgress += BuildProgressHandler; //A1 //
BuildProgressHander is a function that returns void and takes
parameters (object, int)

//equivalent to (!)

this.buildProgress += new BuildProgress(BuildProgressHandler); //A2

// delegate void BuildProgress(object sender, int progressPercent); //
you can put this outside the class, i just repeat it here FYI

// this.BuildComplete += BuildCompleteHandler; //B1 //note format:
name of event on LHS and 'naked' format class method name on RHS!!!

//equivalent to (!)

this.BuildComplete += new EventHandler(BuildCompleteHandler); //B2

//note EventHandler delegate defined by .NET!!! You don't define it
yourself like delegate void BuildProgress above (EventArgs is the base
class)

To summarize: A1 works the same as A2 and B1 works the same as (is =
to) B2, even though to me the formats are radically different.

Shocking stuff dontyathink?

RL
 
J

Jon Skeet [C# MVP]

Regarding delegates used as events in the .NET framework--I've
discovered (for me) a shocking non-standard way that events are fired
when using the System.EventArgs class, which apparently is manditory,
as is the "On" prefix for any member function that uses an "EventArgs"

While databinding may take more notice of On* methods, the language
itself couldn't care less. They're just normal methods. Likewise the
language doesn't know anything about EventArgs or EventHandler.

Now, as for the syntax used for creating delegate instances, this is
just a new feature as of C# 2 - implicit conversion of method groups
to delegate instances.

See http://www.csharpindepth.com/Articles/General/BluffersGuide2.aspx

Jon
 
R

raylopez99

While databinding may take more notice of On* methods, the language
itself couldn't care less. They're just normal methods. Likewise the
language doesn't know anything about EventArgs or EventHandler.

Fair enough, but this is a .NET group so I imply that it's the NET API
that knows this stuff, through databinding (whatever that is, but I
think it's the stuff Alan Cooper invented with Visual drag and drop
code generated by the wizard).
Now, as for the syntax used for creating delegate instances, this is
just a new feature as of C# 2 - implicit conversion of method groups
to delegate instances.

Seehttp://www.csharpindepth.com/Articles/General/BluffersGuide2.aspx

That was good, thanks. I wish I had a bluffer's guide to C# (I've
bought some of their guides in the past for other stuff)

RL

Delegates in C# 2 have a number of improvements over C# 1. The most
important two features are implicit method group conversions and
anonymous methods, both of which make it easier to create new
instances of delegate types. For example:

public void Foo()
{
// Do some stuff
}

// C# 1 code:
ThreadStart ts1 = new ThreadStart(Foo);

// C# 2 code, implicit method group conversion:
ThreadStart ts2 = Foo;

// C# 2, anonymous method:
ThreadStart ts3 = delegate { Console.WriteLine("Hi!"); };

There's a lot more to anonymous methods than meets the eye, by the
way...
 
P

Pavel Minaev

Shocking stuff dontyathink?

Not at all. Aside from a number of things that you've simply got wrong
(such as "On..." methods and EventArgs-style signatures for events
being required), it's all very basic C#, discussed in detail in pretty
much every entry-level book.

By the way, it might be a good idea to check whether this is also true
(as it seems to be for your posts so far, invariably) for whatever it
is you're going to post next. Perhaps it's not worth the bother, after
all.
 
J

Jon Skeet [C# MVP]

raylopez99 said:
Fair enough, but this is a .NET group so I imply that it's the NET API
that knows this stuff, through databinding (whatever that is, but I
think it's the stuff Alan Cooper invented with Visual drag and drop
code generated by the wizard).

But my point is that it's only very specific bits of .NET which care
about how you name event raising methods. For the most part, you can
call them what you like with no ill effects other than breaking
convention.

In particular, your claim that:

<quote>
Eventhandler delegates used in a class can (it's complicated) use a
protected virtual method that fires the event but must have prefix "On"
as the name of the method.
</quote>

is incorrect in the general case.
 
R

raylopez99

Not at all. Aside from a number of things that you've simply got wrong
(such as "On..." methods and EventArgs-style signatures for events
being required), it's all very basic C#, discussed in detail in pretty
much every entry-level book.

Hay bozo: I said: "events are fired when using the System.EventArgs
class, which apparently is manditory,
as is the "On" prefix for any member function that uses an "EventArgs"
type delegate. "

Refute that?
By the way, it might be a good idea to check whether this is also true
(as it seems to be for your posts so far, invariably) for whatever it
is you're going to post next. Perhaps it's not worth the bother, after
all.

Perhaps you can killfile me and avoid having the reply, since you're
obsessive compulsive. Or just take your 20 mg Prozac, like your
doctor says.

RL
 
R

raylopez99

In particular, your claim that:

<quote>
Eventhandler delegates used in a class can (it's complicated) use a
protected virtual method that fires the event but must have prefix "On"
as the name of the method.
</quote>

is incorrect in the general case.

Perhaps the prefix "On" is, I agree. But it seems to me EventArgs-
style signatures have a particular format. I will experiment with
this in Console mode and if there's anything of interest will post a
sample program for future generations to ponder later today.

RL
 
P

Pavel Minaev

Hay bozo:  I said: "events are fired when using the System.EventArgs
class, which apparently is manditory,

It is _not_ mandatory.
as is the "On" prefix for any member function that uses an "EventArgs"
type delegate. "

And neither is this.

With regard to "proof", I can only refer you to the C# 3.0 Language
Specification, available directly from Microsoft:

http://msdn.microsoft.com/en-us/vcsharp/aa336809.aspx

If you can find anything at all in it regarding EventArgs or "On..."
being mandatory, you're welcome to share it with me. In fact, it would
be interesting if you can find any mention of EventArgs whatsoever
aside from the (non-normative) code samples.
 
J

Jon Skeet [C# MVP]

raylopez99 said:
Hay bozo: I said: "events are fired when using the System.EventArgs
class, which apparently is manditory,
as is the "On" prefix for any member function that uses an "EventArgs"
type delegate. "

Refute that?

Very easily:

using System;

class Test
{
public event Action Foo;
public event EventHandler Bar;

protected void FireBar(EventArgs args)
{
Bar(this, args);
}

static void Main()
{
Test t = new Test();
t.Foo += () => Console.WriteLine("First");
t.Bar += (sender, args) => Console.WriteLine("Second");

t.Foo();
t.FireBar(EventArgs.Empty);
}
}

Note that "FireBar" doesn't begin with "On", and "Foo" is an event
which doesn't use EventArgs.
Perhaps you can killfile me and avoid having the reply, since you're
obsessive compulsive. Or just take your 20 mg Prozac, like your
doctor says.

Some of us just care about accuracy, that's all. It would also be
preferable to avoid the ad hominem attacks.
 
J

Jon Skeet [C# MVP]

raylopez99 said:
Perhaps the prefix "On" is, I agree. But it seems to me EventArgs-
style signatures have a particular format. I will experiment with
this in Console mode and if there's anything of interest will post a
sample program for future generations to ponder later today.

Any delegate instance of the type EventHandler has to have the right
signature, yes - but that's true of all delegate types. The type
defines the required (or at least compatible) signature. EventHandler's
signature is
void EventHandler(object sender, EventArgs e)
but there's nothing magical about it - that's just how it's been
defined.
 
R

raylopez99

using System;

class Test
{
    public event Action Foo;
    public event EventHandler Bar;

    protected void FireBar(EventArgs args)
    {
        Bar(this, args);
    }

    static void Main()
    {
        Test t = new Test();
        t.Foo += () => Console.WriteLine("First");
        t.Bar += (sender, args) => Console.WriteLine("Second");

        t.Foo();
        t.FireBar(EventArgs.Empty);
    }

}

Note that "FireBar" doesn't begin with "On", and "Foo" is an event
which doesn't use EventArgs.

Note: this example did not compile (10 errors). Some errors were
easy to fix (I think), like adding <int> in public event Action <int>
Foo, but some, like you "lambda expression" is incomprehensible to
me. Can you please drop the => expression and give a cleaner
example? I'd like to go through it and learn something.
Some of us just care about accuracy, that's all. It would also be
preferable to avoid the ad hominem attacks.

Yes, I hear you, but I think you're just too sensitive. The other
dude didn't complain, but I'll tone it down some.

RL
 
J

Jon Skeet [C# MVP]

raylopez99 said:
Note: this example did not compile (10 errors).

It compiles perfectly for me. Perhaps you're not using a C# 3 compiler,
or .NET 3.5?
Some errors were
easy to fix (I think), like adding <int> in public event Action <int>

Ah, that strongly suggests you've only got .NET 2.0 or 3.0 installed.
Foo, but some, like you "lambda expression" is incomprehensible to
me. Can you please drop the => expression and give a cleaner
example? I'd like to go through it and learn something.

Here's a version which will (I believe) compile with .NET 2.0.

using System;

class Test
{
public event Action<int> Foo;
public event EventHandler Bar;

protected void FireBar(EventArgs args)
{
Bar(this, args);
}

static void Main()
{
Test t = new Test();
t.Foo += delegate { Console.WriteLine("First"); };
t.Bar += delegate { Console.WriteLine("Second"); };

t.Foo(10);
t.FireBar(EventArgs.Empty);
}
}
Yes, I hear you, but I think you're just too sensitive. The other
dude didn't complain, but I'll tone it down some.

I hope so - because you're being *incredibly* rude. You just don't
start calling people "bozo" and recommending they take Prozac - it's
not the way things are done in polite discussions. It's not like this
is the first ad hominem attack you've launched, either. Just because
other people may not respond doesn't make your approach any more
palatable. Bear in mind that you're asking people to help you here -
insulting them isn't going to get you anywhere. Would you act like this
in real life?
 
R

raylopez99

It is _not_ mandatory.

Yes, it is (in my mind's eye). We are talking about two different
things. See the post by Jon Skeet--he has what I have in mind. Never
mind his example doesn't compile. The issue is: when you use
EventArgs, is there a particular format? yes there is. The book
C#3.0 Nutshell by Albahari et al states: "With an EventArgs subclass
in place, ...there are three rules: 1/ it must have a void return
type 2/ it must accept two arguments, the first of type object, adn
the second a subclass of EventArgs; the first argument, object,
indicates the event broadcaster, and the second argument contains the
extra information to convey. 3/ Its name must end in "EventHandler".

Now that's what the book sez. It could be 'convention', or, it could
be manditory. In my mind's eye it's the same thing.

Sorry to flame you BTW, but I found I get more responses on usenet
when I'm rude. I'll tone it down a bit because Jon and Peter are
sensitive souls.

RL
 
J

Jon Skeet [C# MVP]

raylopez99 said:
Yes, it is (in my mind's eye). We are talking about two different
things.

In that case you haven't explained yourself clearly enough. Your
statement that "events are fired when using the System.EventArgs class,
which apparently is mandatory" is wrong in itself. Yes, you have to use
EventArgs for an event *of type EventHandler* but that's a very
different statement.
See the post by Jon Skeet--he has what I have in mind. Never
mind his example doesn't compile.

It does, just not under C# 2. Given that you're reading C# 3.0 in a
Nutshell, it would really help you to have a C# 3 compiler installed.
The issue is: when you use
EventArgs, is there a particular format? yes there is. The book
C#3.0 Nutshell by Albahari et al states: "With an EventArgs subclass
in place, ...there are three rules: 1/ it must have a void return
type 2/ it must accept two arguments, the first of type object, adn
the second a subclass of EventArgs; the first argument, object,
indicates the event broadcaster, and the second argument contains the
extra information to convey. 3/ Its name must end in "EventHandler".

What you didn't explain is that it's under a heading of "Standard Event
Pattern". The pattern is *not* enforced by anything, it's just a
convention. It's worth being very clear about the difference between
patterns/conventions and what is valid code.

It's valid to declare a property with the name @int - but it would be
daft to do so, and violate naming conventions left, right and centre.
Now that's what the book sez. It could be 'convention', or, it could
be manditory. In my mind's eye it's the same thing.

Then your "mind's eye" is incorrect. There's a difference between a
*requirement* and a *recommendation*.
Sorry to flame you BTW, but I found I get more responses on usenet
when I'm rude. I'll tone it down a bit because Jon and Peter are
sensitive souls.

You may get more of a response in terms of *volume* when you're rude,
but you'll find that you actually *learn* a lot more quickly when
you're polite, because people don't need to waste time trying to teach
you manners.
 
R

raylopez99

It compiles perfectly for me. Perhaps you're not using a C# 3 compiler,
or .NET 3.5?

Using 2.0. I rewrote your code to conform with my "old style" and it
works. See below. I don't know what "Action" (a keyword) means, and
your use of 'anonymous' or 'inline' delegates is not for me, though I
understand you can 'capture code' and make it sort of a local variable
that way, though looks too confusing to get into. Note also you have
to input something for EventHandler, namely,
t.FireBar(EventArgs.Empty), so you have to input .Empty, which is
something I agree with, and I think you do too. But you made your
point, and I understand it and was apparently mistaking "convention"
with a hard and fast rule about EventHandler. Thanks for clearing
that up.


namespace DelegateSimple01
{

class Test
{
public delegate void FooEventHandler(int i);

//public event Action<int> Foo;
public event FooEventHandler Fool;
public event EventHandler Bar;
protected void FireBar(EventArgs args)
{
Bar(this, args);
}
static void Main()
{
Test t = new Test();
//t.Foo += delegate { Console.WriteLine("First"); };

t.Fool += new FooEventHandler(Foo);
t.Bar += delegate { Console.WriteLine("Second"); };

t.Fool(10);
t.FireBar(EventArgs.Empty);


}
static void Foo(int ii)
{
Console.WriteLine("First,hello!");
}
}

}

I hope so - because you're being *incredibly* rude. You just don't
start calling people "bozo" and recommending they take Prozac - it's
not the way things are done in polite discussions.

Yes, but this is Usenet.

It's not like this
is the first ad hominem attack you've launched, either. Just because
other people may not respond doesn't make your approach any more
palatable. Bear in mind that you're asking people to help you here -
insulting them isn't going to get you anywhere. Would you act like this
in real life?

Yes, sometimes. And it doesn't hurt. In fact, a study once found that
people who are "jerks" end up with little or no negative things
happening to their career. Early in my career, straight out of
school, one of my bosses, who had real clout, once told me: "after you
leave here [he fired me] you'll never work in this field again, I'll
make sure of it" (because of his prestigious position, even if you
wanted to you could not easily sue him for defamation, not that I
would sue him, since I don't believe in lawsuits). He tried his best,
giving me negative recommendations, and despite him I got a better job
and never looked back. But, that does not mean you should be a jerk--
being nice, as I learned in California, gets the job done easier
(Persian expression about honey attracting flies--then again, shitte
attracts flies too)--but at the end of the day, the nice guys, bad
guys, jerks (good, bad and ugly) end up roughly in the same place,
inline with fortune, fate, and their own innate abilities. However,
having said that, since I appreciate your input and feel you might
stop replying to me, I will tone it down some. Like you say you're
not being paid to answer me.

Thanks for your help. I appreciate it and you've done a lot of good
over the years replying to people (I see some of your posts in the
archives when I Google an answer to a problem).

RL
 
P

Pavel Minaev

Using 2.0.  I rewrote your code to conform with my "old style" and it
works.  See below.  I don't know what "Action" (a keyword) means

It's not a keyword. It's System.Action<T> delegate type declared like
this:

delegate void Action<T>(T arg);

So, basically, a general type for single-argument procedures.

Jon's original code used System.Action (without T), which was
introduced in .NET 3.5, and is essentially a no-argument version of
the above:

delegate void Action();
 
R

raylopez99

namespace DelegateSimple01
{

    class Test
    {
        public delegate void FooEventHandler(int i);

        //public event Action<int> Foo;
        public event FooEventHandler Fool;
        public event EventHandler Bar;
        protected void FireBar(EventArgs args)
        {
            Bar(this, args);
        }
        static void Main()
        {
            Test t = new Test();
            //t.Foo += delegate { Console.WriteLine("First"); };

            t.Fool += new FooEventHandler(Foo);
            t.Bar += delegate { Console.WriteLine("Second"); };

            t.Fool(10);
            t.FireBar(EventArgs.Empty);

        }
        static void Foo(int ii)
        {
            Console.WriteLine("First,hello!");
        }
    }

}

I discovered a 'required' convention that should be followed for
delegates:

the class event handler registering the event, here, t.Fool += new
FooEventHandler(Foo); or, equivalently, t.Fool += Foo; [*1*] should
have the target method that accepts the parameter, namely the method
Foo (here: static void Foo(int ii)
{ Console.WriteLine("First,hello!"); }), in the same class scope as
the class that contains the class event handler (i.e. [*1*] above),
here, Test.

Otherwise, it won't compile. This holds true in Windows Forms too,
and trying to use a scope resolution operators like
"ExternalFormClass.Foo" to get to another class in another form did
not work, so, dare I say it, it must be kind of like a "requirement",
using the term loosely. Anyway I don't see the harm doing it this
'required' way, even if it's not a requirement.

RL
 
J

Jon Skeet [C# MVP]

raylopez99 said:
I discovered a 'required' convention that should be followed for
delegates:

the class event handler registering the event, here, t.Fool += new
FooEventHandler(Foo); or, equivalently, t.Fool += Foo; [*1*] should
have the target method that accepts the parameter, namely the method
Foo (here: static void Foo(int ii)
{ Console.WriteLine("First,hello!"); }), in the same class scope as
the class that contains the class event handler (i.e. [*1*] above),
here, Test.

Otherwise, it won't compile.

The part about having the right parameters is a requirement. The part
about being in the same class isn't. The method has to be accessible
though.

Note that this is only incidentally part of events - it's just to do
with how delegate instances are created. Here's an example creating two
Action<int> instances using methods in a different class - one of which
is an instance method and one of which is a static method.

using System;

class Foo
{
string name;

public Foo(string name)
{
this.name = name;
}

public static void Print(int i)
{
Console.WriteLine("Static: {0}", i);
}

public void PrintWithName(int i)
{
Console.WriteLine("Instance ({0}): {1}", name, i);
}
}

class Test
{
static void Main()
{
Foo f = new Foo("Bar");
Action<int> staticAction = Foo.Print;
Action<int> instanceAction = f.PrintWithName;

staticAction(1);
instanceAction(2);
}
}
This holds true in Windows Forms too,
and trying to use a scope resolution operators like
"ExternalFormClass.Foo" to get to another class in another form did
not work, so, dare I say it, it must be kind of like a "requirement",
using the term loosely. Anyway I don't see the harm doing it this
'required' way, even if it's not a requirement.

I do, if it means code duplication. If you have the required method
available and accessible somewhere else, it would be a pain to have to
copy the code.
 
R

raylopez99

raylopez99 said:
I discovered a 'required' convention that should be followed for
delegates:
the class event handler registering the event, here, t.Fool += new
FooEventHandler(Foo); or, equivalently, t.Fool += Foo; [*1*] should
have the target method that accepts the parameter, namely the method
Foo (here:  static void Foo(int ii)
{  Console.WriteLine("First,hello!");  }), in the same class scope as
the class that contains the class event handler (i.e. [*1*] above),
here, Test.
Otherwise, it won't compile.

The part about having the right parameters is a requirement. The part
about being in the same class isn't. The method has to be accessible
though.

This is true--but perhaps my problem is this (this is a general
question): how do you access (what scope resolution operator, to use
a C++ term) do you use when you are trying to access a class declared
in a child form from the parent form? As I type this, I believe this
might be impossible in the general case, since the child form might be
instantiated by the parent form and "doesn't exist" unless
instantiated, but I guess we can have two scenarios: one being a
static child form that is already instantiated and the other being a
non-static 'new' child form.

Actually to make the question a bit broader (since I'm learning) how
do you access a class declared in the parent form, from the child
form? I haven't done this, but since a child inhereits the parent I
would imagine it's simply: //from inside the child form:
parentform.parentclass.someMethod(). This second question should be
straightforward.
Note that this is only incidentally part of events - it's just to do
with how delegate instances are created. Here's an example creating two
Action<int> instances using methods in a different class - one of which
is an instance method and one of which is a static method.

Thanks, but I didn't see how this is relevant, but it reminds me to
study 'Action' at some point, which looks like a sort of macro
shorthand.

I do, if it means code duplication. If you have the required method
available and accessible somewhere else, it would be a pain to have to
copy the code.

Perhaps, but the assumption is that you can access this code with a
scope resolution operator. But, if you cannot (see my first question
above) then it's safer to simply recopy the function XYZ that is being
registered into the current class. I.e.--
ParentForm_class1.AnEventHandler += XYZ; //with the understanding XYZ
belongs to 'ParentForm_class1'. If, however, XYZ belongs to the child
form, ChildForm, which may never be instantiated, what then? You
cannot do this: ParentForm_class1.AnEventHandler += ChildForm.XYZ;
in the general case, can you? I don't think so, in the most general
case of 'on-the-fly' child form instantiation from the parent form.

RL
 
J

Jon Skeet [C# MVP]

raylopez99 said:
This is true--but perhaps my problem is this (this is a general
question): how do you access (what scope resolution operator, to use
a C++ term) do you use when you are trying to access a class declared
in a child form from the parent form? As I type this, I believe this
might be impossible in the general case, since the child form might be
instantiated by the parent form and "doesn't exist" unless
instantiated, but I guess we can have two scenarios: one being a
static child form that is already instantiated and the other being a
non-static 'new' child form.

I don't think you're using the right terminology for a fair amount of
that paragraph, so a code sample would be helpful.
Actually to make the question a bit broader (since I'm learning) how
do you access a class declared in the parent form, from the child
form? I haven't done this, but since a child inhereits the parent I
would imagine it's simply: //from inside the child form:
parentform.parentclass.someMethod(). This second question should be
straightforward.

Again, code would be helpful. I suspect that when you say "a class
declared in the parent form" you mean "a variable declared in the
parent form" but I don't even know whether you mean "parent" in an
inheritance sense or not.
Thanks, but I didn't see how this is relevant

It's relevant because it means you can separate learning about events
from learning about delegates.
but it reminds me to study 'Action' at some point, which looks like a
sort of macro shorthand.


Perhaps, but the assumption is that you can access this code with a
scope resolution operator.

There's no such operator in C#.
But, if you cannot (see my first question
above) then it's safer to simply recopy the function XYZ that is being
registered into the current class. I.e.--
ParentForm_class1.AnEventHandler += XYZ; //with the understanding XYZ
belongs to 'ParentForm_class1'. If, however, XYZ belongs to the child
form, ChildForm, which may never be instantiated, what then? You
cannot do this: ParentForm_class1.AnEventHandler += ChildForm.XYZ;
in the general case, can you? I don't think so, in the most general
case of 'on-the-fly' child form instantiation from the parent form.

Again, some actual code to talk about would be helpful.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top