Domanda

    

Questa domanda ha già una risposta qui:

    
            
  •              Rendimento in VB.NET                                      8 risposte                          
  •     
    

Come implementare il modello iteratore in VB.NET , che non ha la parola chiave yield ?

È stato utile?

Soluzione

Questo è ora supportato in VS 2010 SP1, con Async CTP, vedere: Iteratori ( C # e Visual Basic) su MSDN e scarica Visual Studio CTP asincrono (versione 3) .

Codice come questo, funziona:

Private Iterator Function SomeNumbers() As IEnumerable
    ' Use multiple yield statements.
    Yield 3
    Yield 5
    Yield 8
End Function

Altri suggerimenti

VB.NET non supporta la creazione di iteratori personalizzati e quindi non ha equivalenti alla parola chiave yield C #. Tuttavia, potresti voler leggere l'articolo KB Come creare un Visual Basic .NET o Visual Classe 2005 di base utilizzabile in una dichiarazione For Each per ulteriori informazioni.

La parola chiave yield di C # impone al compilatore di creare una macchina a stati in background per supportarla. VB.Net non ha la parola chiave yield. Ma ha un costrutto che ti consentirebbe di creare una macchina a stati all'interno di una funzione: Membri di funzioni statiche .

Dovrebbe essere possibile imitare gli effetti di una funzione di ritorno del rendimento creando una classe generica che implementa IEnumerable e la macchina a stati necessaria e inserendo un'istanza come membro statico all'interno della funzione.

Ciò richiederebbe ovviamente l'implementazione della classe al di fuori della funzione. Ma se fatto correttamente, la classe dovrebbe essere riutilizzabile nel caso generale. Tuttavia, non ho giocato abbastanza con l'idea di fornire dettagli di implementazione.

Hmm, sembra che potresti essere sfortunato :

  

Oggi stavo affrontando un problema durante la conversione di C # in VB.NET. C # ha un "rendimento" molto interessante " istruzione utilizzata in un blocco iteratore per fornire un valore all'oggetto enumeratore. VB.NET non ha il "rendimento" parola chiave. Quindi, ci sono alcune soluzioni (nessuna delle quali sono veramente pulite) per aggirare questo. È possibile utilizzare un'istruzione return per restituire il valore se si esegue il ciclo continuo e si desidera interrompere un enumeratore e restituire un singolo valore. Tuttavia, se si desidera restituire l'intera enumerazione, creare un Elenco () di tipo figlio e restituire l'elenco. Dato che di solito lo usi con un IEnumerable, List () funzionerà bene.

È stato scritto un anno fa, non sono sicuro che qualcuno abbia inventato qualcos'altro da allora in poi ..


Modifica: questo sarà possibile nella versione 11 di VB.NET (quella dopo VS2010), è previsto il supporto per gli iteratori. La specifica è disponibile qui .

Tieni presente che l'esecuzione differita e le proprietà di valutazione pigre delle espressioni e dei metodi LINQ ci consentono di implementare in modo efficace iteratori personalizzati fino a quando l'istruzione yield non sarà disponibile in .NET 4.5. La resa viene utilizzata internamente dalle espressioni e dai metodi LINQ.

Il seguente codice lo dimostra.

    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

Di seguito viene fornito un output: 2, 4, 8, 16, 32

In 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;
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top