VB.NET和C#中的按引用传递参数

6

我有一个关于byRef传递参数的问题,我有一个基于VB.NET的类库,在其中定义了一些带有byref参数类型的函数。这些参数是父类对象,当我尝试调用这个函数并在byref参数中传递子类对象时,它在VB.NET中可以工作,但我无法在C#中做同样的事情。

以下是我正在尝试的测试代码:

Public Class Father

        Private _Cast As String
        Public Property Cast() As String
            Get
                Return _Cast
            End Get
            Set(ByVal value As String)
                _Cast = value
            End Set
        End Property

    End Class


 Public Class Son
        Inherits Father

        Private _MyName As String
        Public Property Myname() As String
            Get
                Return _MyName
            End Get
            Set(ByVal value As String)
                _MyName = value
            End Set
        End Property


    End Class

VB的实现类

Public Class Parent

        Public Function Show(ByRef value As Father) As Boolean
            Dim test As String = value.Cast
            Return True
        End Function

// 这里我可以调用 Show 方法并将子对象传递给 ByRef 类型参数,它可以正常工作

Public Function Show2() As Boolean

            Dim s As New Son
            Dim result As Boolean = Show(s)

            Return True
        End Function

    End Class

// 但是当我尝试在C#中做同样的事情时

Parent p = new Parent();
            Son s = new Son();
            Father f = new Father();

            p.Show(ref s);

我收到一个错误,提示儿子无法转换为父亲。我已经测试了VB版本,但是如何让它在C#中工作呢?我的类库以dll格式存在。

提前感谢你的帮助。


Try p.Show(ref ((Father)s) - It'sNotALie.
2
旁注:ByRef 没有任何理由存在,这是无意义的。 - H H
现在来回答你的问题,谁是父亲、父母和儿子?他们在你的情况下如何相关联。发布他们的设计结构和关系。 - S.N
@Nair:他做了。类定义在第一个发布的代码块中。 - Chris Sinclair
1
我觉得这不是你能做的事情。在C#代码中,Parent.Show方法可能会将Father value变量重新分配给不是Son的其他值;也许它会分配一个Daughter实例。虽然我不确定为什么VB可以运行。 - Chris Sinclair
1
请注意,这是使用 Option Strict Off 的情况。如果使用 Option Strict On,你会得到以下错误信息:"Option Strict On 不允许从类型 'Father' 缩小为类型 'Son',在将 'ByRef' 参数 'value' 的值复制回匹配的参数时。" - Mark Hurd
2个回答

11

C#在这方面很严格,传递引用的变量必须与方法参数类型完全匹配。VB.NET对此不太严格,它的编译器会重写你的代码并创建所需类型的变量。下面是C#表达式:

    Son s = new Son();
    Father $temp = (Father)s;
    p.Show(ref $temp);
    s = (Son)$temp;

这很好,但并非没有问题。失败模式是Show()方法将错误类型的对象分配给其参数时。由于参数类型为Father,因此可以创建Father对象。但这会使上面片段中的第4条语句失败,无法将Father转换为Son。这不太好看,异常将在错误的语句处引发,真正的问题位于Show()方法中。您可能要思考一段时间,特别是因为该转换实际上在您的VB.NET源代码中并不可见。Ouch。 C#强制您明确编写上面的片段,从而解决了您的问题。

此时你应该惊呼道:“等等,Show()方法实际上并没有创建一个新对象!” 这是很好的洞察力,你已经找到了这个代码的真正问题,Show()方法不应该声明参数为ByRef。它仅应在方法重新分配参数且需要将更改传播回调用方时使用。最好完全避免使用,在方法的返回值中通过返回对象来返回。在VB.NET中使用Function而不是Sub。


4

ByRef 允许函数修改托管指针并使其指向除 Son 以外的其他内容,因此 C# 不允许直接传递托管指针到 Son。不过,你可以这样做:

Son s = new Son();
Father f = s;
p.Show(ref f);
s = (Son)f; //Success if f still points to a Son, InvalidCastException  otherwise.

然而,如果你的方法Show确实不修改托管指针,那么就没有理由将它作为ByRef传递:只需将其作为ByVal传递,你仍然可以修改对象本身。


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