Eventi abstract e virtual e stranezze del compilatore C# !?!

  In C# quando un evento è dichiarato abstract in una classe, in quella classe non è possibile ne testare se l'evento è null e nemmeno notificare l'evento (errore CS0079, The event can only appear on the left hand side of += or -=).

  Dichiarandolo virtual nella classe base e facendo l'override nella classe derivata, quando l'evento viene notificato dalla classe base vengono ignorate le sottoscrizioni fatte dalla classe derivara (il compilatore crea due field distinti e privati su cui registrare le sottoscrizioni, uno per la classe base e l'altro per la classe derivata).

  Dichiarando l'evento abstract e specificando gli accessor(1) add e remove, quando si indica il body degli accessor il compilatore VC#2003 da l'errore CS0500 (cannot declare a body because it is marked abstract) e quando lo si toglie da l'errore CS0073 (An add or remove accessor must have a body).

 La soluzione c'è(2) ma il compilatore resta... strano!

 _____________

(1)  Gli event in C# dichiarano in automatico una variabile privata di tipo delegate e creano in automatico gli accessor add e remove che permettono di sottoscriversi ad un evento (con la classica sintassi +=) oppure di rimuovere la sottoscrizione (con la classica sintassi -=). Il programmatore quando lo desidera può implementare gli accessor add e remove nel modo che preferisce.
(2) Nella classe base dichiarare il field protected (del tipo di delegate relativo all'evento) e usare questo field per testare se l'evento è null e per notificare l'evento. Nella classe derivata dichiarare l'evento con gli accessor add e remove e nel body implementare l'add e remove facendo uso del field protected della classe base.

Print | posted @ venerdì 13 maggio 2005 12.09

Comments on this entry:

Gravatar # re: Eventi abstract e virtual e stranezze del compilatore C# !?!
by Lorenzo Barbieri at 13/05/2005 14.23

Chissà se il buon Adrian ci illuminerà con qualche spiegazione presa dai meandri delle specifiche... :-D
Gravatar # re: Eventi abstract e virtual e stranezze del compilatore C# !?!
by Luca Minudel at 13/05/2005 15.45

Si questo è pane per i suoi denti, aspetto fiducioso un suo commento.
Gravatar # re: Eventi abstract e virtual e stranezze del compilatore C# !?!
by Adrian Florea at 18/05/2005 22.54

Ciao Luca, ho letto solo adesso il tuo interessante post.

Il paragrafo 17.7.4 dell'ECMA-334 secondo me chiarisce il problema:

> quando un evento è dichiarato abstract in una classe,
> in quella classe non è possibile ne testare se l'evento
> è null e nemmeno notificare l'evento

Lo standard dice:

"An abstract event declaration specifies that the accessors of the event are virtual, but does not provide an actual implementation of the accessors"

Puoi verificare questo sostituendo:

public abstract event FooFiredEvent FooFired;

con:

public event FooFiredEvent FooFired
{
add{}
remove{}
}

e ottieni lo stesso errore CS0079.

Questo chiarisce anche:

> Dichiarando l'evento abstract e specificando gli
> accessor(1) add e remove, quando si indica il body
> degli accessor il compilatore VC#2003 da l'errore

Per quanto riguarda:

> Dichiarandolo virtual nella classe base e facendo
> l'override nella classe derivata, quando l'evento viene
> notificato dalla classe base vengono ignorate le
> sottoscrizioni fatte dalla classe derivara (il
> compilatore crea due field distinti e privati su cui
> registrare le sottoscrizioni, uno per la classe base e
> l'altro per la classe derivata).

non ho capito bene quello che intendi. Potresti postare un esempio?
Gravatar # re: Eventi abstract e virtual e stranezze del compilatore C# !?!
by Luca Minudel at 19/05/2005 10.49

Grazie per avermi chiarito quelle che sembravano stranezze e invece sono il comportamento atteso.

Ecco in fondo il codice del caso virtual / override.

Per quanto riguarda l'abstract, avrei ritenuto più utile lasciare la possibilità di spedificare gli accessor nell'evento abstract (nel C++ è possibile scrivere codice nei metodi pure virtual con lo scopo di richiamarlo all'interno del metodo che lo deriva) permettendo così di testare e notificare l'evento. Ma è solo il mio gusto personale.


--------------------------------------------------
//Classe base
public abstract class DataTableEditorLogic {

public virtual event CustomizeErrorMessageEventHandler ShowingErrorMessage;

private void OnShowingErrorMessage(Operation operation, sys.Exception error, ref string errorMessage) {
if (ShowingErrorMessage != null) {
ErrorMessageEventArgs e = new ErrorMessageEventArgs(operation, error, errorMessage);
ShowingErrorMessage(this, e);
errorMessage = e.EndUserErrorMessage;
}

return;
}
}

//Classe derivata
public class DataTableEditor : DataTableEditorLogic {

public override event CustomizeErrorMessageEventHandler ShowingErrorMessage;
}
Gravatar # re: Eventi abstract e virtual e stranezze del compilatore C# !?!
by Adrian Florea at 19/05/2005 12.22

> avrei ritenuto più utile lasciare la possibilità di
> spedificare gli accessor nell'evento abstract

[...]

> permettendo così di testare e notificare l'evento

Facendo delle prove ho notato che non puoi avere accessors neanche su eventi virtual. Strano. Lo standard dice:

"The accessors of an inherited virtual event can be overridden in a derived class by including an event declaration that specifies an override modifier. This is known as an overriding event declaration. An overriding event declaration does not declare a new event. Instead, it simply specializes the implementations of the accessors of an existing virtual event".

(vedi lo stesso paragrafo dello standard)

però, da quanto pare, va interpretato nel senso che puoi definire accessors solo nell'evento che fa override e questi accessors fanno overriding sugli accessors *generati* per l'evento virtual.

> Dichiarandolo virtual nella classe base e facendo
> l'override nella classe derivata, quando l'evento viene
> notificato dalla classe base vengono ignorate le
> sottoscrizioni fatte dalla classe derivara

// vediamo se ho capito il problema:

using System;

delegate void FooFiredEvent();

class Foo
{
public virtual event FooFiredEvent FooFired;
public void FireFoo()
{
if (FooFired != null)
{
FooFired();
}
}
}

class Bar: Foo
{
public override event FooFiredEvent FooFired;
}

class Test
{
static void DoSomething()
{
Console.WriteLine("Ciao");
}

static void Main()
{
Bar b = new Bar();
Foo f = b;

b.FooFired += new FooFiredEvent(DoSomething);
// qui vorresti Ciao a console?
f.FireFoo();
}
}

Secondo me, la spiegazione sarebbe questa:

Come hai notato anche tu:

> il compilatore crea due field distinti e privati su cui
> registrare le sottoscrizioni, uno per la classe base e
> l'altro per la classe derivata

e quindi virtual sono gli add/remove e non l'evento! Per la classe Bar (quella derivata), il compilatore genera un altro paio di add/remove però per l'evento FooFired della Bar e non per quello della Foo (la classe base)!

La confusione è creata dalla sintassi: virtual sull'event e non sugli accessor.

Non so come interpretare:

"An overriding event declaration does not declare a new event. Instead, it simply specializes the implementations of the accessors of an existing virtual event"

perché a me risulta, come a te, "a new event"...

Bug nelle specifiche? O nel compilatore?
Gravatar # re: Eventi abstract e virtual e stranezze del compilatore C# !?!
by Adrian Florea at 19/05/2005 18.57

> nel C++ è possibile scrivere codice nei metodi pure
> virtual con lo scopo di richiamarlo all'interno del
> metodo che lo deriva

Quindi vorresti poter chiamare dall'add dell'evento override, l'add dell'evento della classe base?

In questo caso avrei in mente una soluzione abbastanza strana ma carina. La lascio un po' "sedimentare" e poi la posto :-)
Gravatar # re: Eventi abstract e virtual e stranezze del compilatore C# !?!
by Luca Minudel at 20/05/2005 0.28

Ok, aspetto il codice ! Lo potrei usare al posto della soluzione che ho adottato (quella al punto 2) che non mi piace del tutto.
Gravatar # Explicitly calling event accessors
by Web Log di Adrian Florea at 20/05/2005 14.50

Your comment:

Title:
Name:
Email:
Website:
 
Italic Underline Blockquote Hyperlink
 
 
Please add 6 and 7 and type the answer here: