По параметрам Ref в VB.NET и C#

У меня есть вопросы, связанные с передачей параметров 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

заранее спасибо

2 ответа

В C# это строго, переменная, передаваемая по ссылке, должна точно соответствовать типу аргумента метода. VB.NET прощает об этом, его компилятор переписывает ваш код и создает переменную требуемого типа. Примерно так, выражаясь в C#:

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

Что приятно, но не без проблем. Режим сбоя - это когда метод Show() назначает новый объект своему аргументу неправильного типа. Разрешено создавать объект Father, поскольку тип аргумента - Father. Это, однако, приведет к тому, что 4-е утверждение в приведенном выше фрагменте не удастся, не может привести Отца к Сыну. Это не так красиво, исключение будет вызвано неправильным оператором, настоящая проблема находится в методе Show(). Вы можете поразмыслить над этим какое-то время, не в последнюю очередь, потому что приведение фактически не видно в исходном коде VB.NET. Уч. C# заставляет вас написать приведенный выше фрагмент явно, что решает вашу проблему.

На этом этапе вы должны воскликнуть "Но подождите, метод Show() на самом деле не создает новый объект!" Это хорошее понимание, и вы обнаружили истинную проблему в этом коде, метод Show() не должен объявлять аргумент ByRef. Его следует использовать только тогда, когда метод переназначает аргумент, и это изменение необходимо распространить обратно вызывающей стороне. Лучше всего избегать, объект должен быть возвращен методом по возвращаемому значению. Функция в VB.NET вместо Sub.

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 и вы все равно сможете изменить сам объект.

Другие вопросы по тегам