Dies ist durchaus sinnvoll und gelegentlich auch nützlich, wenn Sie ein ereignisähnliches Verhalten bereitstellen wollen: Stellen Sie eine abstrakte Klasse bereit, in der alle "Ereignisbehandler" als virtuelle Methoden implementiert sind, die standardmäßig nichts tun.
Ich habe auch persönlich verwendet diese eine Menge für abstrakte Remote-API-Client-Klassen, wo alle Methoden Ausnahmen werfen: Sie sind abstrakt für die Zwecke der Test-Doppel, in der Erwartung, dass unsere Implementierungen die einzige sein Produktion Implementierungen, sondern ermöglicht es den Benutzern, ihre eigenen Testdoubles entweder von Hand oder über Mocking-Frameworks zu erstellen. Die Methoden virtuell statt abstrakt zu machen, bedeutet, dass neue RPCs hinzugefügt werden können, ohne dass dies eine einschneidende Änderung darstellt.
Eine abgeleitete Klasse kann dann überschreiben algunos der Methoden, muss aber keine bestimmte Methode außer Kraft setzen, da nichts abstrakt ist. Es ist immer noch sinnvoll, dass die Klasse abstrakt ist, weil eine Instanz der Basisklasse sinnlos wäre (da alles ein No-op wäre).
Dieses Muster ist jedoch in Java viel verbreiteter als in C#, da man in C# normalerweise nur "richtige" Ereignisse verwenden würde.