为什么C#null在VB6中被翻译为空,而不是空

为什么C#null在VB6中被翻译为空,而不是空,c#,com,vb6,com-interop,C#,Com,Vb6,Com Interop,我有一个引用VB6 dll的C#应用程序。当我将null从C#传递到VB6 dll函数时,null在VB6中被转换为空值(value),而不是空值(object)。例如: // function in vb6 dll that referenced by c# app Public Sub TestFunc(ByVal oValue As Variant) { ... if oValue is Nothing then set oValue = someObject

我有一个引用VB6 dll的C#应用程序。当我将null从C#传递到VB6 dll函数时,null在VB6中被转换为空值(value),而不是空值(object)。例如:

 // function in vb6 dll that referenced by c# app
 Public Sub TestFunc(ByVal oValue As Variant)
 {
   ...
   if oValue is Nothing then
     set oValue = someObject
   end if
   ...

 }

 // main c# code
 private void Form1_Load(object sender, EventArgs e)
 {
    object testObject = new object();
    testObject = null;
    TestFunc(testObject);
 }
当我传递一个对象(非空)时,它将作为对象传递到VB6中。但当null传递到vb6时,它将变为值类型为空,而不是对象类型为Nothing。有人知道为什么吗?当从c#app传递时,我是否可以在VB6中将null强制为Nothing

非常感谢。

您是否尝试过:

Public Sub TestFunc(ByVal oValue As Variant)
 {
   ...
   If oValue Is Nothing Then
     Set oValue = someObject
   ElseIf IsEmpty(oValue) Then
     Set oValue = someObject
   End If
   ...

 }

编辑-我同意Sander Rijken关于为什么返回
Empty
而不是
null
的回答,原因可能是它是一个
ByVal
函数
null
可能被封送到尽可能为“null”的valuetype变量。

更多信息,而不是答案。我刚刚运行了这个VB6 scratch程序,以确认是否可以传递
ByVal
。可能是

Private Sub Form_Load()
  Call TestSub(Nothing)
End Sub
Private Sub TestSub(ByVal vnt As Variant)
  Debug.Print VarType(Nothing)
  Debug.Print VarType(vnt)
  If vnt Is Nothing Then Debug.Print "vnt Is Nothing"
  If IsEmpty(vnt) Then Debug.Print "vnt Is Empty"
End Sub
我得到了以下输出。请注意,9是并表示保存对象引用的变量

 9 
 9 
vnt Is Nothing

我还没有测试过将TestStub移动到另一个组件中,但我认为这仍然有效。因此,我认为将.NET编组到COM可以做得更好

既然不应该修改VB dll中的函数,那么添加一个怎么样

Public Sub TestFuncEx(ByVal oValue As Variant)
{
   If IsEmpty(oValue) Then
    TestFunc(Nothing)
   Else
    TestFunc(oValue)
   End If
}

这可能是因为1)它是一个子函数,不是函数,因此没有返回值;2)您通过值传递,因此它不会修改对象本身。

由于VB6方法的参数是一个变量,您应该测试它是否为空,是否缺失,因为它们可能是“非值或对象”在没有实际值或对象可用时可以传递的

在回答您的问题时,我认为这是因为VB6中的一个变量默认为空,如果您的参数类型为Object,则在您的情况下不会传入任何内容


您可能想尝试从VB.Net中不传递任何内容,看看会发生什么,如果不传递内容持续存在于VB6 DLL中,那么您知道可以传递它,并且可以通过查看IL代码找到答案。

我根据另一个网站的建议,在COM方法调用中使用System.DBNull.Value。这对我来说是有效的,而传递C#null则不行。

我尝试了这一点,效果很好。但我不想更改VB6 dll中的任何代码,因为它可以被其他应用程序使用。我想知道有没有办法强制将空对象作为无对象编组到VB6中?当我引用VB6 Dll时,公共子TestFunc(变量为ByVal oValue)在c#中被转换为Void TestFunc(对象oValue)。它还将初始化对象正确封送为VB6中的对象。它只是错误地将空对象作为值类型封送到vb6.+1中。务实的解决办法。将此新测试置于块
下,如果oValue为空,则。。。如果
结束,则不应更改其他应用程序的行为。假设其他应用程序从未通过此参数的
Empty
。@tifti-我同意MarkJ的观点,为什么不将此代码放在当前VB6代码块下检查
Nothing
?+1?我也这么说-这是一个简单的解决方案,正如MarkJ和Heather已经提到的,不应该影响调用该函数的其他代码(如果是这样的话,我会考虑其他应用程序中的bug,因为函数最初不是编写来处理<代码>空< /COD>特别的)。我同意这将是我在研究定制编组标记的选项时为计时所做的变通。J和Robert建议。非常感谢大家的帮助。
ByVal
并不意味着它必须是值类型,它只是意味着如果传递了一个对象变量,例程就不能将它指向其他对象。VB6变体c按住
查看我的答案了解更多信息。是的,问题可能在封送中,虽然我不确定它是否可修复,但我不知道它是否可修复。我相信.NET封送是非常可定制的,但我对它知之甚少。我认为从VB.NET传递
是值得尝试的,但我已经始终阅读Vb.Net
Nothing
等同于C#
null
。我认为,研究定制从.Net到托管世界Vb的编组的选项更有希望。Net Nothing和C#null是相同的,但生成互操作DLL的互操作代码生成器工作方式不同。我认为这是因为在VB.NET团队独立于C团队工作的开始时,我们有不同的设计目标。我认为VB.NET团队有一个想法来考虑VB.NET如何与VB6代码进行交互,结果使用不同的技术来实现他们的目标。互操作代码生成器不是在VB.NET和C语言中都是相同的吗?当然只有在E的独立版本:<代码> TLBIMP ,并编写C++测试COM DLL,显示NULL= VTSULL,Syp.dnulul.Value= Vtnull NULL。