Доходность в 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;
}
}