SlideShare a Scribd company logo
1 of 11
Download to read offline
Virtual events in C#: something went
wrong
Author: Sergey Khrenov
Date: 18.11.2016
Not so long ago I was working on a new C# diagnostic - V3119 - for the PVS-Studio static code analyzer.
The function of this diagnostic is to detect potentially unsafe constructions in the source code of C#,
related to the usage of virtual and overridden events. Let's try to sort out, what's wrong with virtual
events in C# - the principle of this diagnostic, and why Microsoft doesn't recommend using virtual and
overridden events.
Introduction
I think our readers are quite aware of what virtual mechanisms in C# are. The simplest example would
be an example of virtual methods. In this case, virtuality allows to run the overridden virtual method
according to the object's run-time type. I'll give an illustration using a simple example.
class A
{
public virtual void F() { Console.WriteLine("A.F"); }
public void G() { Console.WriteLine("A.G"); }
}
class B : A
{
public override void F() { Console.WriteLine("B.F"); }
public new void G() { Console.WriteLine("B.G"); }
}
static void Main(....)
{
B b = new B();
A a = b;
a.F();
b.F();
a.G();
b.G();
}
As a result of execution we will have the following:
B.F
B.F
A.G
B.G
Everything is correct. Since both objects a and b have the B type at run-time, then the call of the virtual
method F() for both these objects will lead to the call of the overridden method F() of B class. On the
other hand, a and b objects differ in the compile time type, having A and B types accordingly. That's
why the call of the G() method for each of these objects leads to the call of the corresponding method
for A or B class. You can find more details about the usage of the keywords virtual and override here.
Like methods, properties and indicators, events can also be declared as virtual:
public virtual event ....
You can do this as for "simple" and for events, explicitly implementing accessors add and remove. So,
working with virtual and overridden events in the derived classes, it would be logical to expect behavior
similar to the behavior of the virtual methods. But this is not the case. Moreover, MSDN directly say that
they do not recommend using virtual and overridden events: "Do not declare virtual events in a base
class and override them in a derived class. The C# compiler does not handle these correctly, and it is
unpredictable whether a subscriber to the derived event will actually be subscribing to the base class
event".
However, we do not give up, so let us try to implement "... declare virtual events in a base class and
override them in a derived class".
Experiments
As the first experiment, let us create a console application, where we will have two virtual events in the
base class declared and used (with explicit and implicit implementation of add and remove accessors)
and a derived class, overriding these events:
class Base
{
public virtual event Action MyEvent;
public virtual event Action MyCustomEvent
{
add { _myCustomEvent += value; }
remove { _myCustomEvent -= value; }
}
protected Action _myCustomEvent { get; set; }
public void FooBase()
{
MyEvent?.Invoke();
_myCustomEvent?.Invoke();
}
}
class Child : Base
{
public override event Action MyEvent;
public override event Action MyCustomEvent
{
add { _myCustomEvent += value; }
remove { _myCustomEvent -= value; }
}
protected new Action _myCustomEvent { get; set; }
public void FooChild()
{
MyEvent?.Invoke();
_myCustomEvent?.Invoke();
}
}
static void Main(...)
{
Child child = new Child();
child.MyEvent += () =>
Console.WriteLine("child.MyEvent handler");
child.MyCustomEvent += () =>
Console.WriteLine("child.MyCustomEvent handler");
child.FooChild();
child.FooBase();
}
The result of the exectution will be:
child.MyEvent handler
child.MyCustomEvent handler
Using the debugger or a test output, it's easy to make sure that at the time of the child.FooBase() call,
the values of both variables MyEvent and _myCustomEvent are null, and the program doesn't crash only
because of the conditional access operator upon the attempt to initialize the events MyEvent?.Invoke()
and _myCustomEvent?.Invoke().
So, the MSDN warning was not in vain. It really doesn't work. The subscription to the virtual events of an
object using the Child run time type, doesn't lead to a simultaneous subscription to the events of the
Base class. In the case of implicit implementation of the event, the compiler automatically creates
methods-accessors for it - add and remove, and also a delegate field, which is used to subscribe and
unsubscribe. The problem, apparently, is that if you use a virtual event, the basic and child classes will
have individual (not virtual) delegate-fields that are connected with this event.
In the case of explicit implementation - it is a developer who does that, and takes into account this
peculiarity of virtual events behavior in C#. In the example above, I didn't take into account this
peculiarity, declaring the delegate property _myCustomEvent as protected in the base and derived
classes. Thus, I actually repeated the implementation provided automatically by the compiler for virtual
events.
Let's try to achieve the expected behavior of a virtual event, with the help of the second experiment. To
do this, let's use a virtual and overridden event with explicit implementation of add and remove
accessors, and also a virtual delegate property, related to it. Let's change the text of the program from
the first experiment:
class Base
{
public virtual event Action MyEvent;
public virtual event Action MyCustomEvent
{
add { _myCustomEvent += value; }
remove { _myCustomEvent -= value; }
}
public virtual Action _myCustomEvent { get; set; } //<= virtual
public void FooBase()
{
MyEvent?.Invoke();
_myCustomEvent?.Invoke();
}
}
class Child : Base
{
public override event Action MyEvent;
public override event Action MyCustomEvent
{
add { _myCustomEvent += value; }
remove { _myCustomEvent -= value; }
}
public override Action _myCustomEvent { get; set; } //<= override
public void FooChild()
{
MyEvent?.Invoke();
_myCustomEvent?.Invoke();
}
}
static void Main(...)
{
Child child = new Child();
child.MyEvent += () =>
Console.WriteLine("child.MyEvent handler");
child.MyCustomEvent += () =>
Console.WriteLine("child.MyCustomEvent handler");
child.FooChild();
child.FooBase();
}
Result of the program execution:
child.MyEvent handler
child.MyCustomEvent handler
child.MyCustomEvent handler
Take note of the fact that there were two executions of the handler for the event child.MyCustomEvent.
In debugging mode, it is easy to detect that now, upon the call of _myCustomEvent?.Invoke() in the
FooBase() method, the value of the delegate is not null. Thus, we managed to get the expected behavior
for virtual events only by using events with explicitly implemented accessors add and remove.
You may say that that's great, of course, but we are talking about some synthetic examples from the
theoretical field, so let these virtual and overridden events remain there. I'll give the following
comments:
- You may find yourself in a situation where you're forced to use virtual events. For example,
inheriting from an abstract class that has an abstract event, declared with an implicit
implementation. As a result, you get in your class, an overridden event, which you may use
later. There is nothing dangerous until you choose to inherit from your class, and override this
event again.
- Such constructions are quite rare, but still they can be found in real projects. I was convinced of
this after I implemented the C# diagnostic V3119 for the static code analyzer PVS-Studio. The
diagnostic looks for declarations of virtual or overridden events with implicit implementation
that are used in the current class. A situation is considered unsafe when such constructions are
found, and the class can have derived classes, and the event can be overridden (not sealed).
That is, when hypothetically it is possible to have a situation with the overriding of a virtual or
an already overridden event in a derived class. Warnings that were found in such a way are
given in the next section.
Examples from real projects
To test the quality of PVS-Studio analyzer's work, we use a pool of test projects. After adding the new
rule, V3119, to the analyzer that is devoted to virtual and overridden events, we did a check of the
whole pool of projects. Let's see what warnings we got.
Roslyn
This project has been previously checked, and you can find the article here. Now I just give a list of
analyzer warnings that are related to virtual and overridden virtual events.
PVS-Studio warning: V3119 Calling overridden event 'Started' may lead to unpredictable behavior.
Consider implementing event accessors explicitly or use 'sealed' keyword.
GlobalOperationNotificationServiceFactory.cs 33
PVS-Studio warning: V3119 Calling overridden event 'Stopped' may lead to unpredictable behavior.
Consider implementing event accessors explicitly or use 'sealed' keyword.
GlobalOperationNotificationServiceFactory.cs 34
private class NoOpService :
AbstractGlobalOperationNotificationService
{
....
public override event EventHandler Started;
public override event
EventHandler<GlobalOperationEventArgs> Stopped;
....
public NoOpService()
{
....
var started = Started; //<=
var stopped = Stopped; //<=
}
....
}
In this case, we are most likely dealing with a situation of forced overriding of virtual events. The base
class AbstractGlobalOperationNotificationService is abstract, and has declaration of abstract events
Started and Stopped:
internal abstract class
AbstractGlobalOperationNotificationService :
IGlobalOperationNotificationService
{
public abstract event EventHandler Started;
public abstract event
EventHandler<GlobalOperationEventArgs> Stopped;
....
}
It's not quite clear how the overridden events Started and Stopped will be used further on, because the
delegates are just assigned to the local variables started and stopped, and aren't used in the
NoOpService in any way. However, this situation is potentially unsafe, and the analyzer warns about this.
SharpDevelop
The analysis of the project has also been previously described in the article. I'll give here a list of the
V3119 analyzer warnings.
PVS-Studio warning: V3119 Calling overridden event 'ParseInformationUpdated' may lead to
unpredictable behavior. Consider implementing event accessors explicitly or use 'sealed' keyword.
CompilableProject.cs 397
....
public override event EventHandler<ParseInformationEventArgs>
ParseInformationUpdated = delegate {};
....
public override void OnParseInformationUpdated (....)
{
....
SD.MainThread.InvokeAsyncAndForget
(delegate { ParseInformationUpdated(null, args); }); //<=
}
....
The analyzer detected usage of an overridden virtual event. We'll have a dangerous situation in case of
inheritance from the current class, and overriding of the ParseInformationUpdated event in the derived
class.
PVS-Studio warning: V3119 Calling overridden event 'ShouldApplyExtensionsInvalidated' may lead to
unpredictable behavior. Consider implementing event accessors explicitly or use 'sealed' keyword.
DefaultExtension.cs 127
....
public override event
EventHandler<DesignItemCollectionEventArgs>
ShouldApplyExtensionsInvalidated;
....
protected void ReapplyExtensions
(ICollection<DesignItem> items)
{
if (ShouldApplyExtensionsInvalidated != null)
{
ShouldApplyExtensionsInvalidated(this, //<=
new DesignItemCollectionEventArgs(items));
}
}
....
Again, the analyzer detected usage of an overridden virtual event.
Space Engineers
This project was also previously checked by PVS-Studio. You can find the results of the analysis in this
article. The new V3119 diagnostics issued 2 warnings.
PVS-Studio warning: V3119 Calling virtual event 'OnAfterComponentAdd' may lead to unpredictable
behavior. Consider implementing event accessors explicitly. MyInventoryAggregate.cs 209
PVS-Studio warning: V3119 Calling virtual event 'OnBeforeComponentRemove' may lead to
unpredictable behavior. Consider implementing event accessors explicitly. MyInventoryAggregate.cs
218
....
public virtual event
Action<MyInventoryAggregate, MyInventoryBase>
OnAfterComponentAdd;
public virtual event
Action<MyInventoryAggregate, MyInventoryBase>
OnBeforeComponentRemove;
....
public void AfterComponentAdd(....)
{
....
if (OnAfterComponentAdd != null)
{
OnAfterComponentAdd(....); // <=
}
}
....
public void BeforeComponentRemove(....)
{
....
if (OnBeforeComponentRemove != null)
{
OnBeforeComponentRemove(....);
}
}
....
We are dealing here with the declaration and usage not of overridden, but of virtual events. In general,
the situation is no different from the previous ones.
RavenDB
The RavenDB project is a so called "NoSQL" (or document-oriented) database. Its detailed description is
available on the official website. The project is developed using .NET, and the source code is available on
GitHub. The analysis of RavenDB by the PVS-Studio analyzer detected three V3119 warnings.
PVS-Studio warning: V3119 Calling overridden event 'AfterDispose' may lead to unpredictable behavior.
Consider implementing event accessors explicitly or use 'sealed' keyword. DocumentStore.cs 273
PVS-Studio warning: V3119 Calling overridden event 'AfterDispose' may lead to unpredictable behavior.
Consider implementing event accessors explicitly or use 'sealed' keyword. ShardedDocumentStore.cs
104
Both of these warnings were issued for similar code fragments. Let's take a look at one such fragment:
public class DocumentStore : DocumentStoreBase
{
....
public override event EventHandler AfterDispose;
....
public override void Dispose()
{
....
var afterDispose = AfterDispose; //<=
if (afterDispose != null)
afterDispose(this, EventArgs.Empty);
}
....
}
The event AfterDispose, overridden in the class DocumentStore, is declared as abstract in the base
abstract class DocumentStoreBase:
public abstract class DocumentStoreBase : IDocumentStore
{
....
public abstract event EventHandler AfterDispose;
....
}
As in the previous examples, the analyzer warns us of the potential danger, should the virtual event
AfterDispose be overridden and be used in the classes derived from DocumentStore.
PVS-Studio warning: V3119 Calling virtual event 'Error' may lead to unpredictable behavior. Consider
implementing event accessors explicitly. JsonSerializer.cs 1007
....
public virtual event EventHandler<ErrorEventArgs> Error;
....
internal void OnError(....)
{
EventHandler<ErrorEventArgs> error = Error; //<=
if (error != null)
error(....);
}
....
Here we have declaration and use of a virtual event. Again, there is a risk of undefined behavior.
Conclusion
I think we can stop here and draw the conclusion that we really shouldn't use implicitly implemented
virtual events. Due to the specifics of their implementation in C#, the usage of such events can lead to
undefined behavior. In case you have to use overridden virtual events (for example, upon the derivation
from an abstract class), this should be done with caution, using explicitly defined accessors add and
remove. You can also use the keyword sealed, when declaring a class or an event. And of course, you
should use static code analysis tools, like PVS-Studio for example.

More Related Content

What's hot

Looking for Bugs in MonoDevelop
Looking for Bugs in MonoDevelopLooking for Bugs in MonoDevelop
Looking for Bugs in MonoDevelopPVS-Studio
 
MeetJS Summit 2016: React.js enlightenment
MeetJS Summit 2016: React.js enlightenmentMeetJS Summit 2016: React.js enlightenment
MeetJS Summit 2016: React.js enlightenmentArtur Szott
 
Basic Unit Testing with Mockito
Basic Unit Testing with MockitoBasic Unit Testing with Mockito
Basic Unit Testing with MockitoAlexander De Leon
 
Easymock Tutorial
Easymock TutorialEasymock Tutorial
Easymock TutorialSbin m
 
Mockito with a hint of PowerMock
Mockito with a hint of PowerMockMockito with a hint of PowerMock
Mockito with a hint of PowerMockYing Zhang
 
React.js enlightenment
React.js enlightenmentReact.js enlightenment
React.js enlightenmentArtur Szott
 
Still Comparing "this" Pointer to Null?
Still Comparing "this" Pointer to Null?Still Comparing "this" Pointer to Null?
Still Comparing "this" Pointer to Null?Andrey Karpov
 
Re-checking the ReactOS project - a large report
Re-checking the ReactOS project - a large reportRe-checking the ReactOS project - a large report
Re-checking the ReactOS project - a large reportPVS-Studio
 
NodeJS Spring style Inversifyjs
NodeJS Spring style InversifyjsNodeJS Spring style Inversifyjs
NodeJS Spring style InversifyjsMathieu Breton
 
Redux Thunk - Fu - Fighting with Async
Redux Thunk - Fu - Fighting with AsyncRedux Thunk - Fu - Fighting with Async
Redux Thunk - Fu - Fighting with AsyncArtur Szott
 
Mocking in Java with Mockito
Mocking in Java with MockitoMocking in Java with Mockito
Mocking in Java with MockitoRichard Paul
 
Discussing Errors in Unity3D's Open-Source Components
Discussing Errors in Unity3D's Open-Source ComponentsDiscussing Errors in Unity3D's Open-Source Components
Discussing Errors in Unity3D's Open-Source ComponentsPVS-Studio
 
Comparing PVS-Studio for C# and a built-in Visual Studio analyzer, using the ...
Comparing PVS-Studio for C# and a built-in Visual Studio analyzer, using the ...Comparing PVS-Studio for C# and a built-in Visual Studio analyzer, using the ...
Comparing PVS-Studio for C# and a built-in Visual Studio analyzer, using the ...Ekaterina Milovidova
 
Dependency Injection
Dependency InjectionDependency Injection
Dependency InjectionIndrit Selimi
 
Errors detected in the Visual C++ 2012 libraries
Errors detected in the Visual C++ 2012 librariesErrors detected in the Visual C++ 2012 libraries
Errors detected in the Visual C++ 2012 librariesPVS-Studio
 
33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good TestsTomek Kaczanowski
 

What's hot (20)

Looking for Bugs in MonoDevelop
Looking for Bugs in MonoDevelopLooking for Bugs in MonoDevelop
Looking for Bugs in MonoDevelop
 
MeetJS Summit 2016: React.js enlightenment
MeetJS Summit 2016: React.js enlightenmentMeetJS Summit 2016: React.js enlightenment
MeetJS Summit 2016: React.js enlightenment
 
Basic Unit Testing with Mockito
Basic Unit Testing with MockitoBasic Unit Testing with Mockito
Basic Unit Testing with Mockito
 
Easymock Tutorial
Easymock TutorialEasymock Tutorial
Easymock Tutorial
 
Mockito with a hint of PowerMock
Mockito with a hint of PowerMockMockito with a hint of PowerMock
Mockito with a hint of PowerMock
 
React.js enlightenment
React.js enlightenmentReact.js enlightenment
React.js enlightenment
 
Still Comparing "this" Pointer to Null?
Still Comparing "this" Pointer to Null?Still Comparing "this" Pointer to Null?
Still Comparing "this" Pointer to Null?
 
Re-checking the ReactOS project - a large report
Re-checking the ReactOS project - a large reportRe-checking the ReactOS project - a large report
Re-checking the ReactOS project - a large report
 
NodeJS Spring style Inversifyjs
NodeJS Spring style InversifyjsNodeJS Spring style Inversifyjs
NodeJS Spring style Inversifyjs
 
Redux Thunk - Fu - Fighting with Async
Redux Thunk - Fu - Fighting with AsyncRedux Thunk - Fu - Fighting with Async
Redux Thunk - Fu - Fighting with Async
 
Mock your way with Mockito
Mock your way with MockitoMock your way with Mockito
Mock your way with Mockito
 
Mocking in Java with Mockito
Mocking in Java with MockitoMocking in Java with Mockito
Mocking in Java with Mockito
 
Discussing Errors in Unity3D's Open-Source Components
Discussing Errors in Unity3D's Open-Source ComponentsDiscussing Errors in Unity3D's Open-Source Components
Discussing Errors in Unity3D's Open-Source Components
 
Using Mockito
Using MockitoUsing Mockito
Using Mockito
 
Comparing PVS-Studio for C# and a built-in Visual Studio analyzer, using the ...
Comparing PVS-Studio for C# and a built-in Visual Studio analyzer, using the ...Comparing PVS-Studio for C# and a built-in Visual Studio analyzer, using the ...
Comparing PVS-Studio for C# and a built-in Visual Studio analyzer, using the ...
 
Dependency Injection
Dependency InjectionDependency Injection
Dependency Injection
 
Mockito intro
Mockito introMockito intro
Mockito intro
 
Mockito intro
Mockito introMockito intro
Mockito intro
 
Errors detected in the Visual C++ 2012 libraries
Errors detected in the Visual C++ 2012 librariesErrors detected in the Visual C++ 2012 libraries
Errors detected in the Visual C++ 2012 libraries
 
33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests
 

Viewers also liked

Spine Surgeon in Pune | Brain Surgeon in Pune | Dr.Dilip Kiyawat,Maharashtra
Spine Surgeon in Pune | Brain Surgeon in Pune | Dr.Dilip Kiyawat,MaharashtraSpine Surgeon in Pune | Brain Surgeon in Pune | Dr.Dilip Kiyawat,Maharashtra
Spine Surgeon in Pune | Brain Surgeon in Pune | Dr.Dilip Kiyawat,MaharashtraDrDilip Kiyavat
 
Lectura principios para la igualdad de género.
Lectura principios para la igualdad de género.Lectura principios para la igualdad de género.
Lectura principios para la igualdad de género.EduPeru
 
OnPoint Publications Tax Week in Review 11 4 2016
OnPoint Publications Tax Week in Review 11 4 2016OnPoint Publications Tax Week in Review 11 4 2016
OnPoint Publications Tax Week in Review 11 4 2016OnPoint Publications
 
Proyecto de investigacion
Proyecto de investigacionProyecto de investigacion
Proyecto de investigacionjoal2016_1
 
Guiao de leitura_dos_ovos_misteriosos
Guiao de leitura_dos_ovos_misteriososGuiao de leitura_dos_ovos_misteriosos
Guiao de leitura_dos_ovos_misteriososbibliotecap
 
CV-Gudina 20178
CV-Gudina 20178CV-Gudina 20178
CV-Gudina 20178GUDINA66
 
задания семинар непрямая коммуникация нестерова
задания семинар непрямая коммуникация нестеровазадания семинар непрямая коммуникация нестерова
задания семинар непрямая коммуникация нестероваDaniela K
 
Proyecto blog
Proyecto blogProyecto blog
Proyecto blogjohan107
 
Organizaciones Ágiles y Exponenciales por: Miguel Ángel Martínez
Organizaciones Ágiles y Exponenciales por: Miguel Ángel MartínezOrganizaciones Ágiles y Exponenciales por: Miguel Ángel Martínez
Organizaciones Ágiles y Exponenciales por: Miguel Ángel MartínezYesi Campa
 
La cultura ciudadana en Barranquilla - Colombia
La cultura ciudadana en Barranquilla - ColombiaLa cultura ciudadana en Barranquilla - Colombia
La cultura ciudadana en Barranquilla - ColombiaANA MANOTAS MARTINEZ
 
Test de mantenimiento v03
Test de mantenimiento v03Test de mantenimiento v03
Test de mantenimiento v03dfernando99
 
Conto luisa.ducla cidade.caes_guiao.18paginas
Conto luisa.ducla cidade.caes_guiao.18paginasConto luisa.ducla cidade.caes_guiao.18paginas
Conto luisa.ducla cidade.caes_guiao.18paginasbibliotecap
 

Viewers also liked (17)

Spine Surgeon in Pune | Brain Surgeon in Pune | Dr.Dilip Kiyawat,Maharashtra
Spine Surgeon in Pune | Brain Surgeon in Pune | Dr.Dilip Kiyawat,MaharashtraSpine Surgeon in Pune | Brain Surgeon in Pune | Dr.Dilip Kiyawat,Maharashtra
Spine Surgeon in Pune | Brain Surgeon in Pune | Dr.Dilip Kiyawat,Maharashtra
 
Lectura principios para la igualdad de género.
Lectura principios para la igualdad de género.Lectura principios para la igualdad de género.
Lectura principios para la igualdad de género.
 
Diapositivas Yacuanquer
Diapositivas YacuanquerDiapositivas Yacuanquer
Diapositivas Yacuanquer
 
Aec1 ley de moore pdf
Aec1 ley de moore pdfAec1 ley de moore pdf
Aec1 ley de moore pdf
 
EL fogon llanero y algo mas
EL fogon llanero y algo mas EL fogon llanero y algo mas
EL fogon llanero y algo mas
 
OnPoint Publications Tax Week in Review 11 4 2016
OnPoint Publications Tax Week in Review 11 4 2016OnPoint Publications Tax Week in Review 11 4 2016
OnPoint Publications Tax Week in Review 11 4 2016
 
Tabajo colaborativo
Tabajo colaborativoTabajo colaborativo
Tabajo colaborativo
 
Proyecto de investigacion
Proyecto de investigacionProyecto de investigacion
Proyecto de investigacion
 
Guiao de leitura_dos_ovos_misteriosos
Guiao de leitura_dos_ovos_misteriososGuiao de leitura_dos_ovos_misteriosos
Guiao de leitura_dos_ovos_misteriosos
 
CV-Gudina 20178
CV-Gudina 20178CV-Gudina 20178
CV-Gudina 20178
 
задания семинар непрямая коммуникация нестерова
задания семинар непрямая коммуникация нестеровазадания семинар непрямая коммуникация нестерова
задания семинар непрямая коммуникация нестерова
 
Proyecto blog
Proyecto blogProyecto blog
Proyecto blog
 
Organizaciones Ágiles y Exponenciales por: Miguel Ángel Martínez
Organizaciones Ágiles y Exponenciales por: Miguel Ángel MartínezOrganizaciones Ágiles y Exponenciales por: Miguel Ángel Martínez
Organizaciones Ágiles y Exponenciales por: Miguel Ángel Martínez
 
La cultura ciudadana en Barranquilla - Colombia
La cultura ciudadana en Barranquilla - ColombiaLa cultura ciudadana en Barranquilla - Colombia
La cultura ciudadana en Barranquilla - Colombia
 
Test de mantenimiento v03
Test de mantenimiento v03Test de mantenimiento v03
Test de mantenimiento v03
 
11 liv rx crƒnio e oss crƒnio 353 a 378
11  liv rx crƒnio e oss crƒnio 353 a 37811  liv rx crƒnio e oss crƒnio 353 a 378
11 liv rx crƒnio e oss crƒnio 353 a 378
 
Conto luisa.ducla cidade.caes_guiao.18paginas
Conto luisa.ducla cidade.caes_guiao.18paginasConto luisa.ducla cidade.caes_guiao.18paginas
Conto luisa.ducla cidade.caes_guiao.18paginas
 

Similar to Virtual events in C#: something went wrong

Diving in the Flex Data Binding Waters
Diving in the Flex Data Binding WatersDiving in the Flex Data Binding Waters
Diving in the Flex Data Binding Watersmichael.labriola
 
Microsoft opened the source code of Xamarin.Forms. We couldn't miss a chance ...
Microsoft opened the source code of Xamarin.Forms. We couldn't miss a chance ...Microsoft opened the source code of Xamarin.Forms. We couldn't miss a chance ...
Microsoft opened the source code of Xamarin.Forms. We couldn't miss a chance ...PVS-Studio
 
"Applied Enterprise Metaprogramming in JavaScript", Vladyslav Dukhin
"Applied Enterprise Metaprogramming in JavaScript", Vladyslav Dukhin"Applied Enterprise Metaprogramming in JavaScript", Vladyslav Dukhin
"Applied Enterprise Metaprogramming in JavaScript", Vladyslav DukhinFwdays
 
Working Effectively With Legacy Code
Working Effectively With Legacy CodeWorking Effectively With Legacy Code
Working Effectively With Legacy CodeNaresh Jain
 
Application Frameworks: The new kids on the block
Application Frameworks: The new kids on the blockApplication Frameworks: The new kids on the block
Application Frameworks: The new kids on the blockRichard Lord
 
Scala Future & Promises
Scala Future & PromisesScala Future & Promises
Scala Future & PromisesKnoldus Inc.
 
Source code of WPF samples by Microsoft was checked
Source code of WPF samples by Microsoft was checkedSource code of WPF samples by Microsoft was checked
Source code of WPF samples by Microsoft was checkedPVS-Studio
 
JavaScript: The Good Parts Or: How A C# Developer Learned To Stop Worrying An...
JavaScript: The Good Parts Or: How A C# Developer Learned To Stop Worrying An...JavaScript: The Good Parts Or: How A C# Developer Learned To Stop Worrying An...
JavaScript: The Good Parts Or: How A C# Developer Learned To Stop Worrying An...Doug Jones
 
Paulo morgado what's new in c# 5.0
Paulo morgado   what's new in c# 5.0Paulo morgado   what's new in c# 5.0
Paulo morgado what's new in c# 5.0iseltech
 
Delegateless Coordinators - take 2
Delegateless Coordinators - take 2Delegateless Coordinators - take 2
Delegateless Coordinators - take 2Tales Andrade
 
What’s New In C# 5.0 - iseltech'13
What’s New In C# 5.0 - iseltech'13What’s New In C# 5.0 - iseltech'13
What’s New In C# 5.0 - iseltech'13Paulo Morgado
 
Checking Clang 11 with PVS-Studio
Checking Clang 11 with PVS-StudioChecking Clang 11 with PVS-Studio
Checking Clang 11 with PVS-StudioAndrey Karpov
 
Re-analysis of Umbraco code
Re-analysis of Umbraco codeRe-analysis of Umbraco code
Re-analysis of Umbraco codePVS-Studio
 
SystemVerilog OOP Ovm Features Summary
SystemVerilog OOP Ovm Features SummarySystemVerilog OOP Ovm Features Summary
SystemVerilog OOP Ovm Features SummaryAmal Khailtash
 
Accord.Net: Looking for a Bug that Could Help Machines Conquer Humankind
Accord.Net: Looking for a Bug that Could Help Machines Conquer HumankindAccord.Net: Looking for a Bug that Could Help Machines Conquer Humankind
Accord.Net: Looking for a Bug that Could Help Machines Conquer HumankindPVS-Studio
 
Delegateless Coordinator
Delegateless CoordinatorDelegateless Coordinator
Delegateless CoordinatorTales Andrade
 
JavaScript- Functions and arrays.pptx
JavaScript- Functions and arrays.pptxJavaScript- Functions and arrays.pptx
JavaScript- Functions and arrays.pptxMegha V
 
2. Design patterns. part #2
2. Design patterns. part #22. Design patterns. part #2
2. Design patterns. part #2Leonid Maslov
 
Das kannste schon so machen
Das kannste schon so machenDas kannste schon so machen
Das kannste schon so machenAndré Goliath
 

Similar to Virtual events in C#: something went wrong (20)

Diving in the Flex Data Binding Waters
Diving in the Flex Data Binding WatersDiving in the Flex Data Binding Waters
Diving in the Flex Data Binding Waters
 
Microsoft opened the source code of Xamarin.Forms. We couldn't miss a chance ...
Microsoft opened the source code of Xamarin.Forms. We couldn't miss a chance ...Microsoft opened the source code of Xamarin.Forms. We couldn't miss a chance ...
Microsoft opened the source code of Xamarin.Forms. We couldn't miss a chance ...
 
"Applied Enterprise Metaprogramming in JavaScript", Vladyslav Dukhin
"Applied Enterprise Metaprogramming in JavaScript", Vladyslav Dukhin"Applied Enterprise Metaprogramming in JavaScript", Vladyslav Dukhin
"Applied Enterprise Metaprogramming in JavaScript", Vladyslav Dukhin
 
Working Effectively With Legacy Code
Working Effectively With Legacy CodeWorking Effectively With Legacy Code
Working Effectively With Legacy Code
 
Application Frameworks: The new kids on the block
Application Frameworks: The new kids on the blockApplication Frameworks: The new kids on the block
Application Frameworks: The new kids on the block
 
Scala Future & Promises
Scala Future & PromisesScala Future & Promises
Scala Future & Promises
 
Source code of WPF samples by Microsoft was checked
Source code of WPF samples by Microsoft was checkedSource code of WPF samples by Microsoft was checked
Source code of WPF samples by Microsoft was checked
 
JavaScript: The Good Parts Or: How A C# Developer Learned To Stop Worrying An...
JavaScript: The Good Parts Or: How A C# Developer Learned To Stop Worrying An...JavaScript: The Good Parts Or: How A C# Developer Learned To Stop Worrying An...
JavaScript: The Good Parts Or: How A C# Developer Learned To Stop Worrying An...
 
Paulo morgado what's new in c# 5.0
Paulo morgado   what's new in c# 5.0Paulo morgado   what's new in c# 5.0
Paulo morgado what's new in c# 5.0
 
Delegateless Coordinators - take 2
Delegateless Coordinators - take 2Delegateless Coordinators - take 2
Delegateless Coordinators - take 2
 
What’s New In C# 5.0 - iseltech'13
What’s New In C# 5.0 - iseltech'13What’s New In C# 5.0 - iseltech'13
What’s New In C# 5.0 - iseltech'13
 
Checking Clang 11 with PVS-Studio
Checking Clang 11 with PVS-StudioChecking Clang 11 with PVS-Studio
Checking Clang 11 with PVS-Studio
 
Backbone.js
Backbone.jsBackbone.js
Backbone.js
 
Re-analysis of Umbraco code
Re-analysis of Umbraco codeRe-analysis of Umbraco code
Re-analysis of Umbraco code
 
SystemVerilog OOP Ovm Features Summary
SystemVerilog OOP Ovm Features SummarySystemVerilog OOP Ovm Features Summary
SystemVerilog OOP Ovm Features Summary
 
Accord.Net: Looking for a Bug that Could Help Machines Conquer Humankind
Accord.Net: Looking for a Bug that Could Help Machines Conquer HumankindAccord.Net: Looking for a Bug that Could Help Machines Conquer Humankind
Accord.Net: Looking for a Bug that Could Help Machines Conquer Humankind
 
Delegateless Coordinator
Delegateless CoordinatorDelegateless Coordinator
Delegateless Coordinator
 
JavaScript- Functions and arrays.pptx
JavaScript- Functions and arrays.pptxJavaScript- Functions and arrays.pptx
JavaScript- Functions and arrays.pptx
 
2. Design patterns. part #2
2. Design patterns. part #22. Design patterns. part #2
2. Design patterns. part #2
 
Das kannste schon so machen
Das kannste schon so machenDas kannste schon so machen
Das kannste schon so machen
 

Recently uploaded

Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationkaushalgiri8080
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...ICS
 
XpertSolvers: Your Partner in Building Innovative Software Solutions
XpertSolvers: Your Partner in Building Innovative Software SolutionsXpertSolvers: Your Partner in Building Innovative Software Solutions
XpertSolvers: Your Partner in Building Innovative Software SolutionsMehedi Hasan Shohan
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataBradBedford3
 
Call Girls in Naraina Delhi 💯Call Us 🔝8264348440🔝
Call Girls in Naraina Delhi 💯Call Us 🔝8264348440🔝Call Girls in Naraina Delhi 💯Call Us 🔝8264348440🔝
Call Girls in Naraina Delhi 💯Call Us 🔝8264348440🔝soniya singh
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptkotipi9215
 
Engage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyEngage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyFrank van der Linden
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...Christina Lin
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdfWave PLM
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 
cybersecurity notes for mca students for learning
cybersecurity notes for mca students for learningcybersecurity notes for mca students for learning
cybersecurity notes for mca students for learningVitsRangannavar
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEOrtus Solutions, Corp
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...soniya singh
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...kellynguyen01
 
Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...aditisharan08
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfjoe51371421
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about usDynamic Netsoft
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 

Recently uploaded (20)

Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanation
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
XpertSolvers: Your Partner in Building Innovative Software Solutions
XpertSolvers: Your Partner in Building Innovative Software SolutionsXpertSolvers: Your Partner in Building Innovative Software Solutions
XpertSolvers: Your Partner in Building Innovative Software Solutions
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
 
Call Girls in Naraina Delhi 💯Call Us 🔝8264348440🔝
Call Girls in Naraina Delhi 💯Call Us 🔝8264348440🔝Call Girls in Naraina Delhi 💯Call Us 🔝8264348440🔝
Call Girls in Naraina Delhi 💯Call Us 🔝8264348440🔝
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.ppt
 
Engage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyEngage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The Ugly
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 
cybersecurity notes for mca students for learning
cybersecurity notes for mca students for learningcybersecurity notes for mca students for learning
cybersecurity notes for mca students for learning
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
 
Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdf
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about us
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 

Virtual events in C#: something went wrong

  • 1. Virtual events in C#: something went wrong Author: Sergey Khrenov Date: 18.11.2016 Not so long ago I was working on a new C# diagnostic - V3119 - for the PVS-Studio static code analyzer. The function of this diagnostic is to detect potentially unsafe constructions in the source code of C#, related to the usage of virtual and overridden events. Let's try to sort out, what's wrong with virtual events in C# - the principle of this diagnostic, and why Microsoft doesn't recommend using virtual and overridden events. Introduction I think our readers are quite aware of what virtual mechanisms in C# are. The simplest example would be an example of virtual methods. In this case, virtuality allows to run the overridden virtual method according to the object's run-time type. I'll give an illustration using a simple example. class A { public virtual void F() { Console.WriteLine("A.F"); } public void G() { Console.WriteLine("A.G"); } } class B : A { public override void F() { Console.WriteLine("B.F"); } public new void G() { Console.WriteLine("B.G"); } } static void Main(....)
  • 2. { B b = new B(); A a = b; a.F(); b.F(); a.G(); b.G(); } As a result of execution we will have the following: B.F B.F A.G B.G Everything is correct. Since both objects a and b have the B type at run-time, then the call of the virtual method F() for both these objects will lead to the call of the overridden method F() of B class. On the other hand, a and b objects differ in the compile time type, having A and B types accordingly. That's why the call of the G() method for each of these objects leads to the call of the corresponding method for A or B class. You can find more details about the usage of the keywords virtual and override here. Like methods, properties and indicators, events can also be declared as virtual: public virtual event .... You can do this as for "simple" and for events, explicitly implementing accessors add and remove. So, working with virtual and overridden events in the derived classes, it would be logical to expect behavior similar to the behavior of the virtual methods. But this is not the case. Moreover, MSDN directly say that they do not recommend using virtual and overridden events: "Do not declare virtual events in a base class and override them in a derived class. The C# compiler does not handle these correctly, and it is unpredictable whether a subscriber to the derived event will actually be subscribing to the base class event". However, we do not give up, so let us try to implement "... declare virtual events in a base class and override them in a derived class". Experiments As the first experiment, let us create a console application, where we will have two virtual events in the base class declared and used (with explicit and implicit implementation of add and remove accessors) and a derived class, overriding these events: class Base { public virtual event Action MyEvent;
  • 3. public virtual event Action MyCustomEvent { add { _myCustomEvent += value; } remove { _myCustomEvent -= value; } } protected Action _myCustomEvent { get; set; } public void FooBase() { MyEvent?.Invoke(); _myCustomEvent?.Invoke(); } } class Child : Base { public override event Action MyEvent; public override event Action MyCustomEvent { add { _myCustomEvent += value; } remove { _myCustomEvent -= value; } } protected new Action _myCustomEvent { get; set; } public void FooChild() { MyEvent?.Invoke(); _myCustomEvent?.Invoke(); } } static void Main(...) { Child child = new Child(); child.MyEvent += () => Console.WriteLine("child.MyEvent handler"); child.MyCustomEvent += () => Console.WriteLine("child.MyCustomEvent handler");
  • 4. child.FooChild(); child.FooBase(); } The result of the exectution will be: child.MyEvent handler child.MyCustomEvent handler Using the debugger or a test output, it's easy to make sure that at the time of the child.FooBase() call, the values of both variables MyEvent and _myCustomEvent are null, and the program doesn't crash only because of the conditional access operator upon the attempt to initialize the events MyEvent?.Invoke() and _myCustomEvent?.Invoke(). So, the MSDN warning was not in vain. It really doesn't work. The subscription to the virtual events of an object using the Child run time type, doesn't lead to a simultaneous subscription to the events of the Base class. In the case of implicit implementation of the event, the compiler automatically creates methods-accessors for it - add and remove, and also a delegate field, which is used to subscribe and unsubscribe. The problem, apparently, is that if you use a virtual event, the basic and child classes will have individual (not virtual) delegate-fields that are connected with this event. In the case of explicit implementation - it is a developer who does that, and takes into account this peculiarity of virtual events behavior in C#. In the example above, I didn't take into account this peculiarity, declaring the delegate property _myCustomEvent as protected in the base and derived classes. Thus, I actually repeated the implementation provided automatically by the compiler for virtual events. Let's try to achieve the expected behavior of a virtual event, with the help of the second experiment. To do this, let's use a virtual and overridden event with explicit implementation of add and remove accessors, and also a virtual delegate property, related to it. Let's change the text of the program from the first experiment: class Base { public virtual event Action MyEvent; public virtual event Action MyCustomEvent { add { _myCustomEvent += value; } remove { _myCustomEvent -= value; } } public virtual Action _myCustomEvent { get; set; } //<= virtual public void FooBase() { MyEvent?.Invoke(); _myCustomEvent?.Invoke(); }
  • 5. } class Child : Base { public override event Action MyEvent; public override event Action MyCustomEvent { add { _myCustomEvent += value; } remove { _myCustomEvent -= value; } } public override Action _myCustomEvent { get; set; } //<= override public void FooChild() { MyEvent?.Invoke(); _myCustomEvent?.Invoke(); } } static void Main(...) { Child child = new Child(); child.MyEvent += () => Console.WriteLine("child.MyEvent handler"); child.MyCustomEvent += () => Console.WriteLine("child.MyCustomEvent handler"); child.FooChild(); child.FooBase(); } Result of the program execution: child.MyEvent handler child.MyCustomEvent handler child.MyCustomEvent handler Take note of the fact that there were two executions of the handler for the event child.MyCustomEvent. In debugging mode, it is easy to detect that now, upon the call of _myCustomEvent?.Invoke() in the FooBase() method, the value of the delegate is not null. Thus, we managed to get the expected behavior for virtual events only by using events with explicitly implemented accessors add and remove.
  • 6. You may say that that's great, of course, but we are talking about some synthetic examples from the theoretical field, so let these virtual and overridden events remain there. I'll give the following comments: - You may find yourself in a situation where you're forced to use virtual events. For example, inheriting from an abstract class that has an abstract event, declared with an implicit implementation. As a result, you get in your class, an overridden event, which you may use later. There is nothing dangerous until you choose to inherit from your class, and override this event again. - Such constructions are quite rare, but still they can be found in real projects. I was convinced of this after I implemented the C# diagnostic V3119 for the static code analyzer PVS-Studio. The diagnostic looks for declarations of virtual or overridden events with implicit implementation that are used in the current class. A situation is considered unsafe when such constructions are found, and the class can have derived classes, and the event can be overridden (not sealed). That is, when hypothetically it is possible to have a situation with the overriding of a virtual or an already overridden event in a derived class. Warnings that were found in such a way are given in the next section. Examples from real projects To test the quality of PVS-Studio analyzer's work, we use a pool of test projects. After adding the new rule, V3119, to the analyzer that is devoted to virtual and overridden events, we did a check of the whole pool of projects. Let's see what warnings we got. Roslyn This project has been previously checked, and you can find the article here. Now I just give a list of analyzer warnings that are related to virtual and overridden virtual events. PVS-Studio warning: V3119 Calling overridden event 'Started' may lead to unpredictable behavior. Consider implementing event accessors explicitly or use 'sealed' keyword. GlobalOperationNotificationServiceFactory.cs 33 PVS-Studio warning: V3119 Calling overridden event 'Stopped' may lead to unpredictable behavior. Consider implementing event accessors explicitly or use 'sealed' keyword. GlobalOperationNotificationServiceFactory.cs 34 private class NoOpService : AbstractGlobalOperationNotificationService { .... public override event EventHandler Started; public override event EventHandler<GlobalOperationEventArgs> Stopped; .... public NoOpService() { ....
  • 7. var started = Started; //<= var stopped = Stopped; //<= } .... } In this case, we are most likely dealing with a situation of forced overriding of virtual events. The base class AbstractGlobalOperationNotificationService is abstract, and has declaration of abstract events Started and Stopped: internal abstract class AbstractGlobalOperationNotificationService : IGlobalOperationNotificationService { public abstract event EventHandler Started; public abstract event EventHandler<GlobalOperationEventArgs> Stopped; .... } It's not quite clear how the overridden events Started and Stopped will be used further on, because the delegates are just assigned to the local variables started and stopped, and aren't used in the NoOpService in any way. However, this situation is potentially unsafe, and the analyzer warns about this. SharpDevelop The analysis of the project has also been previously described in the article. I'll give here a list of the V3119 analyzer warnings. PVS-Studio warning: V3119 Calling overridden event 'ParseInformationUpdated' may lead to unpredictable behavior. Consider implementing event accessors explicitly or use 'sealed' keyword. CompilableProject.cs 397 .... public override event EventHandler<ParseInformationEventArgs> ParseInformationUpdated = delegate {}; .... public override void OnParseInformationUpdated (....) { .... SD.MainThread.InvokeAsyncAndForget (delegate { ParseInformationUpdated(null, args); }); //<= }
  • 8. .... The analyzer detected usage of an overridden virtual event. We'll have a dangerous situation in case of inheritance from the current class, and overriding of the ParseInformationUpdated event in the derived class. PVS-Studio warning: V3119 Calling overridden event 'ShouldApplyExtensionsInvalidated' may lead to unpredictable behavior. Consider implementing event accessors explicitly or use 'sealed' keyword. DefaultExtension.cs 127 .... public override event EventHandler<DesignItemCollectionEventArgs> ShouldApplyExtensionsInvalidated; .... protected void ReapplyExtensions (ICollection<DesignItem> items) { if (ShouldApplyExtensionsInvalidated != null) { ShouldApplyExtensionsInvalidated(this, //<= new DesignItemCollectionEventArgs(items)); } } .... Again, the analyzer detected usage of an overridden virtual event. Space Engineers This project was also previously checked by PVS-Studio. You can find the results of the analysis in this article. The new V3119 diagnostics issued 2 warnings. PVS-Studio warning: V3119 Calling virtual event 'OnAfterComponentAdd' may lead to unpredictable behavior. Consider implementing event accessors explicitly. MyInventoryAggregate.cs 209 PVS-Studio warning: V3119 Calling virtual event 'OnBeforeComponentRemove' may lead to unpredictable behavior. Consider implementing event accessors explicitly. MyInventoryAggregate.cs 218 .... public virtual event Action<MyInventoryAggregate, MyInventoryBase> OnAfterComponentAdd; public virtual event
  • 9. Action<MyInventoryAggregate, MyInventoryBase> OnBeforeComponentRemove; .... public void AfterComponentAdd(....) { .... if (OnAfterComponentAdd != null) { OnAfterComponentAdd(....); // <= } } .... public void BeforeComponentRemove(....) { .... if (OnBeforeComponentRemove != null) { OnBeforeComponentRemove(....); } } .... We are dealing here with the declaration and usage not of overridden, but of virtual events. In general, the situation is no different from the previous ones. RavenDB The RavenDB project is a so called "NoSQL" (or document-oriented) database. Its detailed description is available on the official website. The project is developed using .NET, and the source code is available on GitHub. The analysis of RavenDB by the PVS-Studio analyzer detected three V3119 warnings. PVS-Studio warning: V3119 Calling overridden event 'AfterDispose' may lead to unpredictable behavior. Consider implementing event accessors explicitly or use 'sealed' keyword. DocumentStore.cs 273 PVS-Studio warning: V3119 Calling overridden event 'AfterDispose' may lead to unpredictable behavior. Consider implementing event accessors explicitly or use 'sealed' keyword. ShardedDocumentStore.cs 104 Both of these warnings were issued for similar code fragments. Let's take a look at one such fragment: public class DocumentStore : DocumentStoreBase { ....
  • 10. public override event EventHandler AfterDispose; .... public override void Dispose() { .... var afterDispose = AfterDispose; //<= if (afterDispose != null) afterDispose(this, EventArgs.Empty); } .... } The event AfterDispose, overridden in the class DocumentStore, is declared as abstract in the base abstract class DocumentStoreBase: public abstract class DocumentStoreBase : IDocumentStore { .... public abstract event EventHandler AfterDispose; .... } As in the previous examples, the analyzer warns us of the potential danger, should the virtual event AfterDispose be overridden and be used in the classes derived from DocumentStore. PVS-Studio warning: V3119 Calling virtual event 'Error' may lead to unpredictable behavior. Consider implementing event accessors explicitly. JsonSerializer.cs 1007 .... public virtual event EventHandler<ErrorEventArgs> Error; .... internal void OnError(....) { EventHandler<ErrorEventArgs> error = Error; //<= if (error != null) error(....); } .... Here we have declaration and use of a virtual event. Again, there is a risk of undefined behavior.
  • 11. Conclusion I think we can stop here and draw the conclusion that we really shouldn't use implicitly implemented virtual events. Due to the specifics of their implementation in C#, the usage of such events can lead to undefined behavior. In case you have to use overridden virtual events (for example, upon the derivation from an abstract class), this should be done with caution, using explicitly defined accessors add and remove. You can also use the keyword sealed, when declaring a class or an event. And of course, you should use static code analysis tools, like PVS-Studio for example.