Передать метод в качестве аргумента без делегата - PullRequest
0 голосов
/ 23 октября 2019

Требуется ли компилятору C # делегат функции для передачи функции в качестве аргумента другой функции?

В Visual Basic .Net я могу передать функцию, возвращаемое значение которой того же типа, что и аргумент методак самому методу без каких-либо фантазий. Это не представляется возможным в C #, если метод не был написан для принятия делегата функции ??

рабочий vb:

Function DoSomething(r As DataRow())
        '...
End Function

Function CallSomething()
        Dim dt As DataTable
        DoSomething(dt.Select(""))
End Function

C # требует, чтобы вызывающий код назначил переменную и передалчто, или что подпись ссылочной функции включает делегата (полезно знать). Небольшая разница, но я ожидал, что простой вызов метода, сделанный на одном языке, может быть так же легко сделан на другом, так как они оба компилируются в один и тот же IL.

вот эквивалент C #, который я пытался сделать:

string DoSomething(ref DataRow[] r)
{ ///do something }

void CallSomething()
{
    DataTable dt;
    DoSomething(ref dt.Select(""));
}

То, что я имел в виду под "фантазией", было использованием делегатов, я использовал делегаты для более сложных сценариев, таких как назначение обработчиков событий для элементов массива, но я был удивлен, что они потребуются для этого.

Спасибо за ответы. Код VB работает должным образом, ByRef неявно присутствует в VB, вы не можете передать объект, управляемый в кучи. Тем не менее, вот самая простая форма, которую я могу предоставить в VB, если вы используете простой проект форм с одним списком и пропускаете этот код, он должен работать нормально:

Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
        Dim dt As New DataTable("A really great table")
        dt.Columns.Add("Column1", GetType(String))
        dt.Rows.Add("Row1") : dt.Rows.Add("Row2")
        PutRowsInListbox(dt.Select(""))
    End Sub

    Private Function PutRowsInListbox(ByRef r() As DataRow)
        For i As Integer = 0 To r.Length - 1
            Me.ListBox1.Items.Add(r(i).Item("Column1"))
        Next
    End Function
End Class

1 Ответ

4 голосов
/ 23 октября 2019
  1. Ваш код Vb.Net не эквивалентен вашему коду C #. Если вы хотите, чтобы они были эквивалентными, вам нужно удалить ключевое слово ref в коде c # (или добавить ByRef в коде VB.Net).

  2. Оба Visual Basicи C # позволяет этот стиль программирования. Однако обратите внимание, что вы не передаете функцию (или метод) другому методу здесь, ни в Vb, ни в c # - вы просто заполняете массив DataRow результатами метода Select таблицы данных.

  3. Поскольку вы фактически не передаете метод в качестве аргумента, более читаемый код будет состоять в том, чтобы получить результаты метода Select в переменную и передать эту переменную в метод DoSomething- но это скорее вопрос личных предпочтений.

  4. Образец кода C #, который у вас есть в вопросе, не скомпилируется.

Вот эквивалентная и скомпилированная версия кода Vb.Net на C #, которая у вас есть:

void DoSomething(DataRow[] r)
{ 
    //do something 
}

void CallSomething()
{
    DataTable dt = null;
    DoSomething(dt.Select(""));
}

Конечно, это выкинет NullReferenceException, если только выфактически инициализировать dt значением вместо null.

Кстати, ByRef не является неявным. Передача ссылочных типов не означает передачу их по ссылке. Это распространенное заблуждение.

Когда вы передаете ссылочный тип методу, на самом деле происходит передача самой ссылки по значению. Вы можете легко проверить это самостоятельно, если попытаетесь переназначить ссылку внутри метода - вы все равно увидите старое значение вне метода, если не указали ByRef.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...