将VB.NET变量设置为C#的null。

5
根据Visual Basic的 Nothing MSDN 条目Nothing 表示数据类型的默认值。
一些人已经指出 "some"," ... Nothing 关键字实际上等同于 C# 的 default(T) 关键字"。
这给我最近正在处理的多语言解决方案中带来了一些异常行为。具体而言,当 VB.NET 异步方法返回 Nothing 时,我在 C# 端遇到了不止几次的 TargetInvocationException
是否可以在 VB.NET 项目中设置变量为 C# 的 null 并能够在 C# 和 VB.NET 中测试该 null 值?
这里有一段代码片段没有按预期工作。C# 项目将 VB.NET 项目作为引用导入。
VB.NET 方面:
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# 侧

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
}

当VB.NET的AnotherMethod成功时,不会抛出任何异常。但是,当它不成功并且tcs的结果设置为Nothing时,一切都会崩溃。
如何有效地将SetResult设置为Nothing而不会导致异常,或者如何将SetResult设置为C#的null

5
我可能错了,但在C#方面,你似乎试图将空值传递给.ToString(),这可能会导致抛出“空值”错误。另外,告诉我们你得到的错误信息,"falls on its head"并不像"system.whatever返回了一个值X,而它期望的是Y"那样具有信息量。 - Nikerym
1
异常的 InnerException 是什么? - Will
1
获取的异常是一个 TargetInvocationException,其消息为“在 mscorlib.dll 中发生了类型为 'System.Reflection.TargetInvocationException' 的第一次机会异常”。Visual Studio 显示“源不可用”页面,也没有可用的堆栈跟踪。 - Alex Essilfie
1
你的第三个示例对我来说毫无意义。即使结果值为null,也没有理由await task;应该失败。 DoSomething()方法始终返回非空对象,因此task本身始终非空,因此await task应始终有效。 结果为null,但您从未在第三个示例中使用它,因此它为null并不是问题。 除此之外,un-lucky的答案解决了您的问题:与“无”相比,“null”没有问题…您也不允许在VB中取消引用“无”! - Peter Duniho
1
".ToString()" 方法或 "await()" 不能处理 null,这就是你得到异常的原因。 - sujith karivelil
显示剩余7条评论
3个回答

2

这不是由于从Nothing转换为null的原因。这里有一些例子,可以证明C#接受Nothing作为null

Vb类库代码:

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

调用此类库的C#代码:

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

这段代码可以正常运行,并且返回result=null,即没有被转换为null的内容
现在来看你的情况:
当函数返回Nothing时,它肯定会被转换为null,但是.ToString()方法或await()无法处理null,这就是你遇到异常的原因。
  • null.ToString()(null).ToString() 会报错:The operator '.' cannot be applied to operand of type '<null>'

  • await(null) 在中不被允许,会报错:cannot await null

以下内容可能对你有所帮助:
ClassVb classLibObj = new ClassVb();
var temp = classLibObj.Dosomething();
var result = temp == null ? "" : temp.ToString();  

1
整个“这可能会帮助你”的部分可以写成var result = (new ClassVb().DoSomething() ?? "").ToString(); - Arthur Rey

0

在阅读了不幸的声明后,我的错误变得明显:

  • null.ToString()(null).ToString() 报告 The operator '.' cannot be applied to operand of type '<null>'
  • await(null) 在 c# 中不被允许,它会报告 cannot await null

原来是因为我在 C# 代码中将 result 变量设置为 string,所以无法从 Object(VB.NET 的 Task(Of Object) 返回类型)转换而来,除非进行 .ToString()(string)(await Method()) 操作。使用这两个过程中的任何一个也会导致 NullReferenceException

最终,我终于弄清楚了自己做错了什么。我首先将返回的 Task<object> 分配给一个变量,然后在等待后检查其结果是否为 null。因此,我得到了适合我的目的的代码,就像这样。
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
    }
}

感谢nikerymPeter Duniho的贡献。我因为连续熬夜超过20个小时而太累了,没有注意到他们所指出的问题。但是让我困惑的是,为什么我遇到了一个TargetInvokationException而不是一个NullReferenceException

你会收到TargetInvocationException异常,是因为await的工作方式:只有在你声明代码的命名方法中,第一个await之前的代码实际上才存在。其余的代码被放入延续(实际上是封装状态机的单个方法)中,在等待任务完成后被调用。如果你查看了TargetInvocationException的内部异常,你会看到实际描述出了问题的NullReferenceException - Peter Duniho

0

我曾经看到一个相关问题的解决方法是将VB项目将'Nothing'强制转换为'Object'类型,以确保它是与引用类型对应的默认值(例如,C# null),并作为此类接收到C#项目,而不是某些值类型的默认值(例如,整数类型的0):

params.Item2.SetResult(CObj(Nothing))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接