Поиск сокращенной документации лямбда-вызовов - PullRequest
1 голос
/ 28 октября 2019

Я всегда имел проблемы с невозможностью var / Dim переменной неявно при использовании блока Using для объявления контекста данных, который возвращает начальное значение переменной. Например,

Dim classifications As IEnumerable(Of RT_Classification)
Using dc As New MyDataContext
    classifications = dc.RT_Classifications.OrderBy(Function(c) c.Order).ToList()
End Using

тип RT_Classification должен быть указан явно при объявлении переменной. Сравните с Using, не ограничиваясь только запросом

Dim classifications = dc.RT_Classifications.OrderBy(Function(c) c.Order).ToList()

, в котором вы получите что-то неявное, аналогичное var в c #. Но тогда контекст данных должен содержать объявление и охватывать весь контекст переменной classifications, что нежелательно.

Я думал об использовании лямбды, которая в основном решает проблемы

Dim classifications =
    (Function()
        Using dc As New MyDataContext
            Return dc.RT_Classifications.OrderBy(Function(c) c.Order).ToList()
        End Using
    End Function).Invoke()

но кажется немного громоздким. Однако, зная сокращение () для .Invoke() и предложение IDE для удаления ( ), я придумал этот странно выглядящий, но рабочий код

Dim classifications =
    Function()
        Using dc As New MyDataContext
            Return dc.RT_Classifications.OrderBy(Function(c) c.Order).ToList()
        End Using
    End Function()

Обратите внимание на трейлингEnd Function(), который был новым для меня. У меня вопрос: как долго это доступно и есть ли недостатки в его использовании, прошлые потенциальные проблемы с читабельностью?

1 Ответ

3 голосов
/ 28 октября 2019

Обратите внимание, что End Function() не является специальным синтаксисом. Это в точности эквивалентно вашему вызову f(), или если вы должны были заключить все выражение в скобки.

Перед синтаксическим анализом сокращения () компилятор компилирует все лямбда-выражения и перемещает их вотдельный метод и заменяет его в вашем коде делегатом, указывающим на этот метод. Поэтому, когда компилятор возобновляет анализ вашего кода, все, что он видит, это что-то вроде: ThisIsADelegate().

Это становится очевидным, если вы декомпилируете свое приложение, используя инструмент, подобный ILSpy .

Оригинальный код:

Public Class TheseAreLambdas
    Dim values As String() = {"This", "word", "is", "the", "longest"}

    Dim classifications =
        Function()
            Return values.OrderBy(Function(s) s.Length).ToList()
        End Function()

    Public Sub DoSomething()
        'I used DirectCast just to reduce mess in the decompiled code. Not necessary otherwise.
        MessageBox.Show(DirectCast(classifications, List(Of String)).Count.ToString())
    End Sub
End Class

Декомпилированный код:

public class TheseAreLambdas
{
    private string[] values;
    private object classifications;

    public TheseAreLambdas()
    {
        /*
            All variable initializations are automatically moved to the constructor.
        */

        //Our array of values.
        values = new string[5]
        {
            "This",
            "word",
            "is",
            "the",
            "longest"
        };

        //Our lambda expression, moved to a method called "_Lambda$__1", wrapped in
        //a compiler-generated delegate and invoked on the spot (notice the parenthesis on the end).
        classifications = new VB$AnonymousDelegate_1<List<string>>(_Lambda$__1)();
    }

    public void DoSomething()
    {
        MessageBox.Show(((List<string>)classifications).Count.ToString());
    }

    [CompilerGenerated]
    private List<string> _Lambda$__1() //Our lambda expression used for the "classifications" variable.
    {
        return values.OrderBy((string s) => s.Length).ToList();
    }

    [CompilerGenerated]
    private static int _Lambda$__2(string s)
    {
        return s.Length;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...