问题
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