Доходность в VB.NET

C# имеет ключевое слово yield. VB.NET не хватает этого ключевого слова. Как программисты Visual Basic обошлись без этого ключевого слова? Они реализуют свой собственный класс итераторов? Или они пытаются и код, чтобы избежать необходимости итератора?

Ключевое слово yield приводит к тому, что компилятор выполняет некоторое кодирование за кулисами. Реализация итераторов в C# и ее последствия (часть 1) имеют хороший пример этого.

8 ответов

Примечание: этот ответ старый. С тех пор блоки итераторов были добавлены в VB.NET

C# переводит ключевое слово yield в конечный автомат во время компиляции. VB.NET не имеет ключевого слова yield, но у него есть собственный механизм для безопасного встраивания состояния в функцию, которая нелегко доступна в C#.

C# static Ключевое слово обычно переводится в Visual Basic с помощью Shared ключевое слово, но есть два места, где все становится запутанным. Во-первых, статический класс C# на самом деле является модулем в Visual Basic, а не классом Shared (можно подумать, что они позволят вам кодировать его в любом случае в Visual Basic, но это не так). Другое дело, что VB.NET имеет свой собственный Static ключевое слово. Тем не мение, Static имеет другое значение в VB.NET.

Вы используете Static ключевое слово в VB.NET, чтобы объявить переменную внутри функции, и когда вы делаете, переменная сохраняет свое состояние при вызове функции. Это отличается от простого объявления частного статического члена класса в C#, потому что статический член функции в VB.NET гарантированно также является поточно-ориентированным, так как компилятор преобразует его для использования класса Monitor во время компиляции.

Так зачем писать все это здесь? Ну, должно быть возможно создать универсальный универсальный Iterator<T> класс (или Iterator(Of T) в VB.NET). В этом классе вы реализуете конечный автомат, используемый C#, с Yield() а также Break() методы, которые соответствуют ключевым словам C#. Тогда вы могли бы использовать статический экземпляр (в смысле VB.NET) в функции, чтобы в конечном итоге он мог выполнять почти ту же работу, что и C#. yield примерно в том же объеме кода (исключая саму реализацию класса, поскольку она будет бесконечно многократно использоваться).

Я не слишком заботился о доходности, чтобы попробовать это сам, но это должно быть выполнимо. Тем не менее, это также далеко не тривиально, так как член команды C# Эрик Липперт называет это " самым сложным преобразованием в компиляторе".

Я также пришел к выводу, что с тех пор, как я написал первый черновой вариант более года назад, до тех пор, пока не выйдет Visual Studio 2010, по-настоящему это невозможно, так как для этого потребуется отправить несколько лямбда-выражений в класс Iterator, и поэтому На практике нам нужна поддержка .NET 4 для многострочных лямбд.

Async CTP включает в себя поддержку Yield в VB.NET

См. Итераторы в Visual Basic для получения информации об использовании.

И теперь он входит в комплект поставки Visual Studio 2012!

Есть хорошая статья Использование итераторов в VB Теперь Билл Маккарти в Visual Studio Magazine об эмуляции yield в VB.NET В качестве альтернативы дождитесь следующей версии Visual Basic.

К счастью, теперь у нас есть Yield вернуть
Вот пример из моего проекта + реализация интерфейса с System.Collections.Generic.IEnumerable(T) функция:

Public Class Status
    Implements IStatus

    Private _statusChangeDate As DateTime
    Public Property statusChangeDate As DateTime Implements IStatus.statusChangeDate
        Get
            Return _statusChangeDate
        End Get
        Set(value As Date)
            _statusChangeDate = value
        End Set
    End Property

    Private _statusId As Integer
    Public Property statusId As Integer Implements IStatus.statusId
        Get
            Return _statusId
        End Get
        Set(value As Integer)
            _statusId = value
        End Set
    End Property

    Private _statusName As String
    Public Property statusName As String Implements IStatus.statusName
        Get
            Return _statusName
        End Get
        Set(value As String)
            _statusName = value
        End Set
    End Property

    Public Iterator Function GetEnumerator() As IEnumerable(Of Object) Implements IStatus.GetEnumerator
        Yield Convert.ToDateTime(statusChangeDate)
        Yield Convert.ToInt32(statusId)
        Yield statusName.ToString()
    End Function

End Class

Public Interface IStatus
    Property statusChangeDate As DateTime
    Property statusId As Integer
    Property statusName As String
    Function GetEnumerator() As System.Collections.Generic.IEnumerable(Of Object)
End Interface

Вот как я извлекаю все свойства снаружи:

For Each itm As SLA.IStatus In outputlist
    For Each it As Object In itm.GetEnumerator()
        Debug.Write(it & " ")
    Next
    Debug.WriteLine("")
Next

Лично я просто пишу свой собственный класс итераторов, который наследуется от IEnumerator(Of T). Требуется некоторое время, чтобы понять это правильно, но я думаю, что в конце лучше написать это правильно, а затем попытаться избежать этого. Другой метод, который я сделал, - это написание рекурсивного метода, который возвращает IEnumerable(Of T), просто возвращает List(Of T) и использует.AddRange.

VB.NET имеет Iterator ключевое слово https://docs.microsoft.com/en-us/dotnet/visual-basic/language-reference/modifiers/iterator

С Visual Studio 2012 похоже

Надеюсь, это будет в прошлом с будущей версией VB. Поскольку итераторы на самом деле приобретают большое значение с новыми парадигмами (особенно LINQ в сочетании с ленивой оценкой), это, насколько я знаю из блога Пола Вика, имеет довольно высокий приоритет. С другой стороны, Пол больше не является главой команды VB, и у меня еще не было времени, чтобы посмотреть выступления PCD.

Тем не менее, если вам интересно, они связаны в блоге Пола.

Код ниже дает вывод

2, 4, 8, 16, 32

В VB.NET,

Public Shared Function setofNumbers() As Integer()
    Dim counter As Integer = 0
    Dim results As New List(Of Integer)
    Dim result As Integer = 1
    While counter < 5
        result = result * 2
        results.Add(result)
        counter += 1
    End While
    Return results.ToArray()
End Function

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    For Each i As Integer In setofNumbers()
        MessageBox.Show(i)
    Next
End Sub

В C#

private void Form1_Load(object sender, EventArgs e)
{
    foreach (int i in setofNumbers())
    {
        MessageBox.Show(i.ToString());
    }
}

public static IEnumerable<int> setofNumbers()
{
    int counter=0;
    int result=1;
    while (counter < 5)
    {
        result = result * 2;
        counter += 1;
        yield return result;
    }
}
Другие вопросы по тегам