Convert C# to VB,NET: Event with a delegate type that has a return type

感情迁移 提交于 2019-12-25 08:59:23

问题


This is the original source-code written in 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));
        }
    }
}

Using an online translator, I get this VB.NET code:

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

The compiler marks the event declaration with this error message:

Events cannot be declared with a delegate type that has a return type.

And the Instance.UnitResolve calls inside the GetUnitByName() method with this error message:

Public Event UnitResolve As UnitResolveEventHandler' is an event, and cannot be called directly.

How can I properly translate the code from C# to VB.NET without losing functionality?


回答1:


The customary way of returning a value from an event handler to the invocation of the event is through an argument---either a member of the event arguments class, or through a ByRef parameter on the delegate.

If you have control over ResolveEventArgs and the event handler routines, you could do something like this:

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

In the body of your handler (assuming the typical declaration of the event arguments as e), instead of Return (return value):

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

Then, the body of your For Each loop would look like this:

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

As an aside, the original C# code has a thread-safety issue. It could throw a NullReferenceException in the event that the last subscribed handler is removed between the null check and reading the invocation list. Whether this is serious (or a concern at all) depends on where and how it's being used. The usual way of addressing this is to store to a temporary, then do the null check and invocation list on the temporary. If you're using a recent version of the .NET languages, then you can skip the null check and use the ?. operator, which should also be safe against the particular thread-safety issue.




回答2:


The original C# source code is bad; event handlers shouldn’t return values. You’ll have to make it not-an-event:

Public UnitResolve As UnitResolveEventHandler

and use Delegate.Combine manually to add event handler:

Instance.UnitResolve = Delegate.Combine(Instance.UnitResolve, newHandler)


来源:https://stackoverflow.com/questions/43174571/convert-c-sharp-to-vb-net-event-with-a-delegate-type-that-has-a-return-type

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!