.net vb.net

Rendimiento en VB.NET



(8)

Nota: Esta respuesta es vieja ahora. Desde entonces se han agregado bloques Iterator a VB.NET

C # traduce la palabra clave yield en una máquina de estados en tiempo de compilación. VB.NET no tiene la palabra clave yield, pero sí tiene su propio mecanismo para incrustar de manera segura el estado dentro de una función que no está fácilmente disponible en C #.

La palabra clave static C # normalmente se traduce a Visual Basic utilizando la palabra clave Shared , pero hay dos lugares donde las cosas se confunden. Una es que una clase estática de C # es realmente un Módulo en Visual Basic en lugar de una clase Compartida (uno pensaría que le dejarían codificar de cualquier manera en Visual Basic, pero noooo). La otra es que VB.NET tiene su propia palabra clave Static . Sin embargo, Static tiene un significado diferente en VB.NET.

Utiliza la palabra clave Static en VB.NET para declarar una variable dentro de una función, y cuando lo hace, la variable conserva su estado en todas las llamadas a funciones. Esto es diferente a simplemente declarar un miembro de clase estática privada en C #, porque se garantiza que un miembro de función estática en VB.NET también será seguro para subprocesos, ya que el compilador lo traduce para usar la clase Monitor en tiempo de compilación.

Entonces, ¿por qué escribir todo esto aquí? Bueno, debería ser posible construir una clase Iterator<T> genérica reutilizable (o Iterator(Of T) en VB.NET). En esta clase, implementaría la máquina de estado utilizada por C #, con los métodos Yield() y Break() que corresponden a las palabras clave C #. Entonces podría usar una instancia estática (en el sentido VB.NET) en una función para que finalmente pueda hacer casi el mismo trabajo que el yield C # en aproximadamente la misma cantidad de código (descartando la implementación de la clase en sí misma, ya que sería infinitamente reutilizable).

No me ha importado lo suficiente sobre el rendimiento para intentarlo, pero debería ser factible. Dicho esto, tampoco es trivial, ya que Eric Lippert, miembro del equipo de C #, lo llama " la transformación más complicada del compilador ".

También he llegado a la conclusión desde que escribí el primer borrador de esto hace más de un año que no es realmente posible de una manera significativa hasta que sale Visual Studio 2010, ya que requeriría enviar múltiples lambdas a la clase Iterator y así ser realmente práctico, necesitamos el soporte de .NET 4 para lambdas de múltiples líneas.

C # tiene la palabra clave llamada yield . VB.NET carece de esta palabra clave. ¿Cómo han solucionado los programadores de Visual Basic la falta de esta palabra clave? ¿Implementan ellos poseen clase de iterador? ¿O intentan codificar para evitar la necesidad de un iterador?

La palabra clave yield obliga al compilador a hacer algo de código detrás de escena. La implementación de iteradores en C # y sus consecuencias (parte 1) tiene un buen ejemplo de eso.


Afortunadamente ahora tenemos retorno de Yield
aquí hay un ejemplo de mi proyecto + implementación de una interfaz con la función 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

Así es como extraigo todas las propiedades del exterior:

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


Con suerte, esto será algo del pasado con la próxima versión de VB. Dado que los iteradores están ganando mucha importancia con los nuevos paradigmas (especialmente LINQ en combinación con la evaluación perezosa), esto tiene una alta prioridad, por lo que sé del blog de Paul Vick. Por otra parte, Paul ya no es el jefe del equipo de VB y aún no he tenido tiempo de ver las conversaciones de PCD.

Aún así, si estás interesado, están vinculados en el blog de Paul .



El siguiente código da la salida

2, 4, 8, 16, 32

En 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; } }


Está el lindo artículo Use Iterators en VB Now de Bill McCarthy en Visual Studio Magazine sobre cómo emular el yield en VB.NET. Alternativamente, espere la próxima versión de Visual Basic.


Personalmente, escribo mi propia clase de iterador que hereda de IEnumerator (Of T). Se necesita algún tiempo para hacerlo bien, pero creo que al final es mejor escribirlo y luego tratar de evitarlo. Otro método que he hecho es escribir un método recursivo que devuelve IEnumerable (Of T) y simplemente devuelve List (Of T) y usa .AddRange.