Ceci est le code source original écrit en C #

public delegate Unit UnitResolveEventHandler(object sender, ResolveEventArgs args);

public event UnitResolveEventHandler UnitResolve;

public static Unit GetUnitByName(string name) {
    Instance.unitsByName.TryGetValue(name, out result);
    if (Instance.UnitResolve != null) {
        foreach (UnitResolveEventHandler handler in Instance.UnitResolve.GetInvocationList()) {
            result = handler(Instance, new ResolveEventArgs(name));
        }
    }
}

En utilisant un traducteur en ligne, j'obtiens ce code VB.NET:

Public Delegate Function UnitResolveEventHandler(sender As Object, args As ResolveEventArgs) As Unit

Public Event UnitResolve As UnitResolveEventHandler

Public Shared Function GetUnitByName(name As String) As Unit
    Instance.unitsByName.TryGetValue(name, result)
    If Instance.UnitResolve IsNot Nothing Then
        For Each handler As UnitResolveEventHandler In Instance.UnitResolve.GetInvocationList()
            result = handler(Instance, New ResolveEventArgs(name))
        Next
    End If
End Function

Le compilateur marque la déclaration d'événement avec ce message d'erreur:

Les événements ne peuvent pas être déclarés avec un type de délégué qui a un type de retour.

Et les appels Instance.UnitResolve dans la méthode GetUnitByName() avec ce message d'erreur:

Événement public UnitResolve As UnitResolveEventHandler 'est un événement et ne peut pas être appelé directement.

Comment puis-je traduire correctement le code de C # vers VB.NET sans perdre de fonctionnalités?

0
ElektroStudios 3 avril 2017 à 02:17

2 réponses

Meilleure réponse

La manière habituelle de renvoyer une valeur d'un gestionnaire d'événement à l'invocation de l'événement est via un argument --- soit un membre de la classe des arguments d'événement, soit via un paramètre ByRef sur le délégué.

Si vous avez le contrôle sur ResolveEventArgs et les routines du gestionnaire d'événements, vous pouvez faire quelque chose comme ceci:

Public Class ResolveEventArgs
    '...
    Public ReturnValue As Unit
    '...
End Class

Dans le corps de votre gestionnaire (en supposant la déclaration typique des arguments d'événement comme e), au lieu de Return (return value):

e.ReturnValue = (return value) 'substitute for (return value) as appropriate

Ensuite, le corps de votre boucle For Each ressemblerait à ceci:

Dim args As New ResolveEventArgs(name)
handler(Instance, args)
result = args.ReturnValue

En passant, le code C # d'origine a un problème de sécurité des threads. Il pourrait lancer un NullReferenceException dans le cas où le dernier gestionnaire abonné serait supprimé entre la vérification de null et la lecture de la liste d'appel. Le fait que cela soit sérieux (ou préoccupant) dépend de l'endroit et de la manière dont il est utilisé. La manière habituelle de résoudre ce problème est de stocker dans un temporaire, puis de faire la vérification de null et la liste d'invocation sur le temporaire. Si vous utilisez une version récente des langages .NET, vous pouvez ignorer la vérification de null et utiliser l'opérateur ?., qui devrait également être sûr contre le problème particulier de sécurité des threads.

3
Craig 3 avril 2017 à 15:29

Le code source C # d'origine est incorrect; les gestionnaires d'événements ne doivent pas renvoyer de valeurs. Vous devrez en faire un événement:

Public UnitResolve As UnitResolveEventHandler

Et utilisez Delegate.Combine manuellement pour ajouter un gestionnaire d'événements:

Instance.UnitResolve = Delegate.Combine(Instance.UnitResolve, newHandler)
1
Ry- 2 avril 2017 à 23:28