Laden...

Events mit Lock werfen NullReferenceException

Erstellt von FischeFr vor 5 Jahren Letzter Beitrag vor 5 Jahren 1.676 Views
F
FischeFr Themenstarter:in
3 Beiträge seit 2018
vor 5 Jahren
Events mit Lock werfen NullReferenceException

Hallo zusammen!

Ich habe ein kleines Projekt gestartet, bei dem PowerShell-Code in einem C#-Programm ausgeführt wird. In Sachen Events könnte ich jetzt von euch etwas Hilfe gebrauchen. Ich kämpfe den ganzen Tag schon mit folgender Fehlermeldung:

Fehlermeldung:
System.Reflection.TargetInvocationException: Ein Aufrufziel hat einen Ausnahmefehler verursacht. ---> System.ArgumentNullException: Der Wert darf nicht NULL sein.
bei System.Threading.Monitor.Enter(Object obj)
bei PSService.PowershellService.ServiceEventsForScript.add_Stop(EventHandler`1 value)
--- Ende der internen Ausnahmestapelüberwachung ---
bei System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
bei System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
bei System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
bei System.Reflection.EventInfo.AddEventHandler(Object target, Delegate handler)
bei System.Management.Automation.PSLocalEventManager.ProcessNewSubscriber(PSEventSubscriber subscriber, Object source, String eventName, String sourceIdentifier, PSObject data, Boolean supportEvent, Boolean forwardEvent)
bei System.Management.Automation.PSLocalEventManager.SubscribeEvent(Object source, String eventName, String sourceIdentifier, PSObject data, ScriptBlock action, Boolean supportEvent, Boolean forwardEvent, Int32 maxTriggerCount)
bei Microsoft.PowerShell.Commands.ObjectEventRegistrationBase.EndProcessing()
bei System.Management.Automation.CommandProcessorBase.Complete()

Dieses Problem trifft auf, wenn das PowerShell-Skript versucht, einen Subscribe-Vorgang auf ein von mir bereitgestelltes Event auszuführen. Ein entsprechender (sinnfreier) Versuchscode sieht folgendermaßen aus:

            public event EventHandler<EventArgs> StopEvent;
            public event EventHandler<EventArgs> Stop
            {
                add
                {
                    lock (StopEvent)
                    {
                        StopEvent += value;
                    }
                }
                remove
                {
                    lock (StopEvent)
                    {
                        StopEvent -= value;
                    }
                }
            }

Vermutlich spielt die PowerShell-Zeile keine Rolle, aber vollständigkeitshalber lautet sie wie folgt:

Register-ObjectEvent -InputObject $Host.PrivateData.Events -EventName 'StopEvent' -SourceIdentifier 'PSService_Stop' -ErrorAction Stop | Out-Null

Bei Verwendung von "StopEvent" klappt alles prima, bei "Stop" bekomme ich die obige Fehlermeldung. "StopEvent" ist hier nur testweise eingefügt. Das "echte" Event, an das weitergeleitet werden muss ist in einer anderen Klasse. Hat von euch jemand eine Idee, was da schief läuft?

16.806 Beiträge seit 2008
vor 5 Jahren

Der Fehler ist, dass Du dem lock() ein Null übergibst; das sieht man auch in der Fehlermeldung.
Und StopEvent ist hier wohl null.

lock() sollte man immer mit Lockobjekten verwenden; nicht mit "irgendwas".
Der Sinn, wieso Du hier überhaupt lockst, erschließt sich mir nicht.

[Artikel] Debugger: Wie verwende ich den von Visual Studio?

F
FischeFr Themenstarter:in
3 Beiträge seit 2018
vor 5 Jahren

Ich danke dir!

Ich war wohl so vertieft, dass ich immer die falsche Zeile angesehen hab. Null locken ist natürlich keine gute Idee 😃

Das Locking hab ich von einem Beispiel von Microsoft (blind) übernommen.

16.806 Beiträge seit 2008
vor 5 Jahren

Das Locking hab ich von einem Beispiel von Microsoft (blind) übernommen.

Kann mir nicht ganz vorstellen, dass das das reine Beispiel von Microsoft ist.
Und wenn doch, dann gibt es in den Samples die Möglichkeit Fehler zu korrigieren.
Link zum Beispiel?

T
2.219 Beiträge seit 2008
vor 5 Jahren

Ich hab beim suchen nach locking bei C# nur das Beispiel gefunden:
https://docs.microsoft.com/de-de/dotnet/csharp/language-reference/keywords/lock-statement

Ansonsten wäre es ratsam, wenn du als Lock Objekt eine Instanz von Object verwendest.
Einen EventHandler sollte man hier nicht als Lock Objekt missbrauchen, ist kein guter Stil und nicht sinn eines Event Handlers.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

16.806 Beiträge seit 2008
vor 5 Jahren

Ich hab beim suchen nach locking bei C# nur das Beispiel gefunden:

>

Warten wir doch mal ab, welches Beispiel er nennt. Raten oder für ihn suchen bringt ja nichts 😉

Einen EventHandler sollte man hier nicht als Lock Objekt missbrauchen, ist kein guter Stil und nicht sinn eines Event Handlers.

Mit Stil hat das wenig zutun; es ist technisch falsch.
Der Sinn eines Eventhandlers wird durch das lock() auch nicht beeinflusst.
Aber er hat es ja ohnehin bereits nun verstanden.

F
FischeFr Themenstarter:in
3 Beiträge seit 2018
vor 5 Jahren

Danke zusammen - jetzt funktionierts.

Der Lock auf einen Event ist gleich mehrfach dämlich:- ist null, wenn noch keine Subscription vorliegt

  • Object wird bei jedem Subscribe durch ein neues (Ergebnis von Delegate.Combine) ausgetauscht

Eigentlich weiß ich das, aber ich bin einfach gestern zu lange vorm Rechner gesessen. War geistig nicht mehr ganz fit 🤔

Ich hatte folgendes Beispiel gemeint. Allerdings benutzen die ein "lockObject", das im Beispiel nicht deklariert wird. Hier das Event zu benutzen war wohl auf meinem eigenen Mist gewachsen.

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/events/how-to-implement-custom-event-accessors

16.806 Beiträge seit 2008
vor 5 Jahren

Vielleicht nicht 100% zum Copy geeignet, aber das Objekt heisst ja objectLock; das sagt ja ziemlich genau, was es ist.
Und wenn man dann in die Doku von lock() schaut, wird es auch gezeigt.

Daher muss ich Dir sagen, dass Du da der Doku unrecht getan hast; die Doku zeigt nicht, dass Du den Event nehmen sollst.
Sonst würde hier ja auch lock (PreDrawEvent) stehen und nicht lock (objectLock) ;-)