Шаблон итератора в VB.NET (C # будет использовать yield!)

Как реализовать шаблон итератора в VB.NET, в котором нет ключевого слова yield ?


person c00ke    schedule 30.10.2008    source источник


Ответы (6)


Теперь это поддерживается в VS 2010 SP1 с Async CTP, см. Итераторы (C # и Visual Basic) в MSDN и загрузить Visual Studio Async CTP ( Версия 3).

Такой код работает:

Private Iterator Function SomeNumbers() As IEnumerable
    ' Use multiple yield statements.
    Yield 3
    Yield 5
    Yield 8
End Function
person Sam Saffron    schedule 19.04.2011

VB.NET не поддерживает создание настраиваемых итераторов и, следовательно, не имеет эквивалента ключевому слову yield в C #. Однако вы можете прочитать статью базы знаний Как сделать Visual Basic .NET или Visual Базовый класс 2005, который можно использовать в инструкции For Each для получения дополнительной информации.

person Jasper Bekkers    schedule 30.10.2008

Ключевое слово C # yield заставляет компилятор создавать конечный автомат в фоновом режиме для его поддержки. VB.Net не имеет ключевого слова yield. Но у него есть конструкция, которая позволит вам создать конечный автомат внутри функции: Статические функции-члены.

Должна быть возможность имитировать эффекты возвращаемой функции yield путем создания универсального класса, который реализует IEnumerable, а также необходимого конечного автомата, и размещения экземпляра в качестве статического члена внутри вашей функции.

Это, конечно, потребует реализации класса вне функции. Но если все сделано правильно, в общем случае класс можно будет использовать повторно. Однако я недостаточно поиграл с этой идеей, чтобы предоставить какие-либо подробности реализации.

person Joel Coehoorn    schedule 30.10.2008
comment
Привет, Джоэл, ты упомянул эту идею по крайней мере дважды. Хотите развить свою идею дальше? - person Andrew Harry; 27.01.2009
comment
Я изучил это немного глубже и больше не уверен, что вы можете создать такой же конечный автомат, как ключевое слово yield в C # в статической локальной переменной VB.Net. Не то чтобы это было бы невозможно, но это определенно не было бы тривиально, и, в конце концов, вам все равно пришлось бы написать какой-то странный код, назначенный машине. Даже этого нельзя было сделать в Visual Studio 2005, так как для этого потребовались бы лямбда-выражения. - person Joel Coehoorn; 23.09.2009

Хм, похоже, вы не повезло:

Сегодня я боролся с проблемой при преобразовании некоторых C # в VB.NET. В C # есть действительно классный оператор yield return, который используется в блоке итератора для предоставления значения объекту перечислителя. VB.NET не имеет ключевого слова yield. Итак, есть несколько решений (ни одно из которых не является действительно чистым), чтобы обойти это. Вы можете использовать оператор return для возврата значения, если вы выполняете цикл и хотите прервать работу перечислителя и вернуть одно значение. Однако, если вы хотите вернуть все перечисление, создайте List () дочернего типа и верните список. Поскольку вы обычно используете это с IEnumerable, List () будет работать нормально.

Это было написано год назад, я не уверен, что с тех пор кто-нибудь придумал что-нибудь лучше.


Изменить: это будет возможно в версии 11 VB.NET (после VS2010), планируется поддержка итераторов. Спецификация доступна здесь.

person Jeff Atwood    schedule 30.10.2008

Имейте в виду, что свойства отложенного выполнения и отложенного вычисления выражений и методов LINQ позволяют нам эффективно реализовывать настраиваемые итераторы до тех пор, пока оператор yield не станет доступен в .NET 4.5. Yield используется внутри выражений и методов LINQ.

Следующий код демонстрирует это.

    Private Sub AddOrRemoveUsersFromRoles(procName As String,
                                      applicationId As Integer,
                                      userNames As String(),
                                      rolenames As String())
    Dim sqldb As SqlDatabase = CType(db, SqlDatabase)
    Dim command As DbCommand = sqldb.GetStoredProcCommand(procName)
    Dim record As New SqlDataRecord({New SqlMetaData("value", SqlDbType.VarChar,200)})
    Dim setRecord As Func(Of String, SqlDataRecord) =
        Function(value As String)
            record.SetString(0, value)
            Return record
        End Function
    Dim userNameRecords As IEnumerable(Of SqlDataRecord) = userNames.Select(setRecord)
    Dim roleNameRecords As IEnumerable(Of SqlDataRecord) = rolenames.Select(setRecord)
    With sqldb
        .AddInParameter(command, "userNames", SqlDbType.Structured, userNameRecords)
        .AddInParameter(command, "roleNames", SqlDbType.Structured, roleNameRecords)
        .AddInParameter(command, "applicationId", DbType.Int32, applicationId)
        .AddInParameter(command, "currentUserName", DbType.String, GetUpdatingUserName)
        .ExecuteNonQuery(command)
    End With
End Sub
person Richard Collette    schedule 07.02.2012

Ниже приведены результаты: 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

In 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;
    //List<int> results = new List<int>();
    int result=1;
    while (counter < 5)
    {
      result = result * 2;
      counter += 1;
      yield return result;
    }
}
person meenakshisundaram muthukrishna    schedule 02.05.2011