5

According to the MSDN entry for Nothing (Visual Basic)

Nothing represents the default value of a data type.

It has also been noted by some that "...the Nothing keyword is actually equivalent to C#’s default(T) keyword".

This has been giving me some anomalous behaviour in a multi-language solution I have been working on recently. Specifically I have been getting with more than a few TargetInvocationExceptions being thrown at the C# end when the VB.NET async methods return Nothing.

Is it possible to set a variable in the VB.NET projects to C#'s null and be able to test for this null value in both C# and VB.NET.


Here is a snippet that is not behaving as expected. The C# project imports the VB.NET project as a reference.

VB.NET Side

Public Function DoSomething() As Task(Of Object)
    Dim tcs = New TaskCompletionSource(Of Object)
    Dim params = Tuple.Create("parameters", tcs)

    AnotherMethod(params)

    Return tcs.Task
End Function

Public Sub AnotherMethod(params As Tuple(Of String, TaskCompletionSource(Of Object))
    ' do some activities
    If result = "Success" Then
        params.Item2.SetResult("we were successful") ' result can also be of different type
    Else
        params.Item2.SetResult(Nothing)  ' could this be the source of the exception?
    End If
End Sub

C# Side

public async void AwaitSomething1()
{
    var result = "";
    result = (await DoSomething()).ToString(); // fails if Result is Nothing
}

public async void AwaitSomething2()
{
    var result = "";
    result = (string)(await DoSomething());    // fails if Result is Nothing
}

public async void AwaitSomething3()
{
    var task = DoSomething();
    await task;                                // also fails if Result is Nothing
}

There is no exception thrown when VB.NET's AnotherMethod is successful. However, when it is not successful and tcs's result is set to Nothing, everything falls on its head.

How can I effectively SetResult to Nothing without resulting in an exception or, otherwise, how can I SetResult to C#'s null?

12
  • 5
    i could be wrong, but on the c# side it looks like your trying to pass a null value to the .ToString() Which could result in a "null value" error being thrown, alternativly give us the erorr your getting "falls on it's head" isn't as informative as "system.whatever returned a value of X when it expected Y" Commented Aug 21, 2015 at 4:30
  • 1
    What is the exception's InnerException ? Commented Aug 21, 2015 at 4:35
  • 1
    The exception obtained is a TargetInvocationException with the message "A first chance exception of type 'System.Reflection.TargetInvocationException' occurred in mscorlib.dll". Visual Studio displays the Source Not Available page and there are no stack traces available either. Commented Aug 21, 2015 at 4:36
  • 1
    Your third example doesn't make sense to me. There's no reason that await task; should fail, even if the result value is null. The DoSomething() method always returns a non-null object, so task itself is always non-null, and so await task should always be valid. The result is null, but you never bother to use it in that third example, so it being null is not a problem. Other than that, the answer from un-lucky addresses your concerns: there's not a problem with Nothing vs null...you wouldn't be allowed to dereference Nothing in VB either! Commented Aug 21, 2015 at 5:43
  • 1
    .ToString() method or await() is not capable of handling null that's the reason for the exception you are getting. Commented Aug 21, 2015 at 5:51

3 Answers 3

2

This is not because of conversion from Nothing to null. Here i have some example for you where C# accepts Nothing as null:

Vb Class Library Code:

Public Class ClassVb
    Public Function Dosomething() As Task(Of Object)
        Return Nothing
    End Function
End Class

C# that Invoke This Class Library :

using vbclassLib;
  class Program
    {
     static void Main(string[] args)
        {
            ClassVb classLibObj = new ClassVb();
            var result = classLibObj.Dosomething();//result=null
        }
    } 

Which works fine and gives result=null, ie., Nothing is converted as null

Let me come to your scenario:

In your scenario, when the function returns Nothing its definitely converted to null but .ToString() method or await() is not capable of handling null that's the reason for the exception you are getting.

  • null.ToString() or (null).ToString() says that The operator '.' cannot be applied to operand of type '<null>'.

  • await(null) will not be allowed by c#, it says cannot await null.

This may help you:

ClassVb classLibObj = new ClassVb();
var temp = classLibObj.Dosomething();
var result = temp == null ? "" : temp.ToString();  
Sign up to request clarification or add additional context in comments.

1 Comment

The whole This may help you part can be written var result = (new ClassVb().DoSomething() ?? "").ToString();
1

I've seen a related issue resolved by having the VB project cast 'Nothing' to the 'Object' type to ensure that it is the default value corresponding to reference types (e.g., C# null) and received by the C# project as such, instead of the default value of some value type (e.g., 0 for an integer type):

params.Item2.SetResult(CObj(Nothing))

Comments

0

My error became apparent after reading un-lucky's statement:

  • null.ToString() or (null).ToString() says that The operator '.' cannot be applied to operand of type '<null>'.
  • await(null) will not be allowed by c#, it says cannot await null.

It turns out that because I had set the result variable in the C# code to string, it was not possible to convert from Object (as in the VB.NET's return type of Task(Of Object)) without having to do a .ToString() or (string)(await Method()). Using either of these two procedures also result in a NullReferenceException.

I was finally able to figure out what I was doing wrong by first assigning the Task<object> returned to a variable and then checking its result for null after awaiting. Thus, I finished up with code like this which suits my purpose.

public class CSharpClass
{
    public async void AwaitSomething()
    {
        var task = new VbNetClass().DoSomething();
        await task;
        // test task.Result for null
        var result = (task.Result ?? "method was unsuccessful").ToString();

        // rest of code follows
    }
}

Thanks to nikerym and Peter Duniho for their contribution. I was too tired from staying up for over 20 hours to notice the point they were making. What beats me though is why I had a TargetInvokationException instead of a NullReferenceException.

1 Comment

You get TargetInvocationException because of the way await works: only the code up to the first await is actually in the named method where you've declared the code. The rest of the code is put into continuations (actually, a single method encapsulating a state machine), which are invoked on completion of the awaited task. If you had looked at the inner exception of the TargetInvocationException, you'd have seen the NullReferenceException that actually described what was going wrong.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.