VB.NET中“yield return”的等价语法是什么?

使用下面的C#代码,您将如何在Visual Basic中编写它? 它想说什么?

using System; using System.Collections.Generic; using System.IO; using System.Windows; using System.Windows.Media; using System.Windows.Media.Imaging; namespace Microsoft.LiveLabs.Pivot { ///  /// Tile Builder class ///  public static class TileBuilder { ///  /// Specifies which images are required in the images array used in CreateTile /// according to the Morton fractal pattern used by Seadragon. ///  ///  /// Usage of this and CreateTile are kind of tricky. Here's an example: /// Say you have a results set that is a collection of items like so: { item1, item2, ..., item100 } /// Since Seadragon expects the tiles to be laid out in a Morton pattern, /// level 6 will look like the following: /// /// -------------------------- /// |0 1 4 5 | 16 17... /// |2 3 6 7 | 18 19 /// |8 9 12 13 | 24 25 /// |10 11 14 15 | 26 27 /// |----------------------- /// |32 33 36 37 | 48 49 /// |34 35 38 39 | 50 51... /// |. . /// |. . /// . . /// /// Each tile at level 6 is 4x4, so the dashes represent tile boundaries. Now, say /// you want to build 0,0. You need the images on that tile. The ids 0, 1, 4, 5... /// represent the ids in your result set, { item1, item2, ..., item100 }. Calling /// this method tells you the ids to use for a given tile. You then must retrieve /// the necessary images out the result set, and supply them in the order this /// method gave you to CreateTile. This will result in a correctly built tile /// that Seadragon can use. ///  /// Number of images in the full set. /// The level to which each image will be downsampled. /// The row number which specifies what images to render. /// The row number which specifies what images to render. /// The size of the tile to return. public static IEnumerable GetTileIds( int imageCount, int level, int row, int column, int tileSize) { // Calculate upper-left hand corner of tile in image space (1 unit = 1 image) int levelSize = (int)Math.Pow(2, level); int imagePerSide = tileSize / levelSize; int xOffset = row * imagePerSide; int yOffset = column * imagePerSide; if (imagePerSide <= 0) { throw new ArgumentOutOfRangeException("Level is greater than the maximum depth allowed by the tile size, or the tile size is 0."); } // Loop through x and y in image space, starting at the upper-left // hand corner of the tile. Find all ids on the given tile. for (int x = 0; x < imagePerSide; x++) { for (int y = 0; y < imagePerSide; y++) { int n = XYToMorton(x + xOffset, y + yOffset); if (n < imageCount) { yield return n; } } } } ///  /// Create a tile for a collection according to the Morton fractal /// pattern used by Seadragon. ///  ///  /// See GetTileIds for more information. ///  /// The total number of images in the collection. /// Jpeg images to render on this tile. /// If this is null, a blank tile will be returned. /// See GetTileIds remarks for more information. /// The level to which each image will be downsampled. /// The row number which specifies what images to render. /// The row number which specifies what images to render. /// The size of the tile to return. /// The stream to use to output the result. public static void CreateTile( int imageCount, IEnumerable images, int level, int row, int column, int tileSize, string fileType, Stream output) { // Calculate upper-left hand corner of tile in image space (1 unit = 1 image). int levelSize = (int)Math.Pow(2, level); int imagePerSide = tileSize / levelSize; int xOffset = row * imagePerSide; int yOffset = column * imagePerSide; if (imagePerSide <= 0) { throw new ArgumentOutOfRangeException("Level is greater than the maximum depth allowed by the tile size, or the tile size is 0."); } if (output == null) { throw new ArgumentNullException("The given output stream is null."); } // Create the tile. WriteableBitmap outputBitmap = new WriteableBitmap( tileSize, tileSize, 96, 96, PixelFormats.Bgr24, null); // If images is null, return a blank tile. if (images != null) { // Loop through the tile in relative x and y image-space. IEnumerator imageEnumerator = images.GetEnumerator(); for (int x = 0; x < imagePerSide; x++) { for (int y = 0; y < imagePerSide; y++) { // Convert to Morton id-space from the absolute image-space (to get absolute, add offsets). int n = XYToMorton(x + xOffset, y + yOffset); if (n < imageCount) { if (imageEnumerator.MoveNext()) { if (imageEnumerator.Current == null) { continue; } // Compute the pixel location int locX = levelSize * x; int locY = levelSize * y; int width = 0; int height = 0; imageEnumerator.Current.ImageSize(out width, out height); MemoryStream imageStream = new MemoryStream(imageEnumerator.Current.ImageData); // Determine the largest tile size to the nearest power of two for // this image: 2^ceil(lg max(width, height)). double maxTileSize = Math.Pow(2, Math.Ceiling(Math.Log(Math.Max(width, height), 2))); // Downsample to the correct size and decompress the image. The correct size // is total dimenion of the image * level size / max tile size required for // total width. Think of this as dividing the dimensions by two foreach // levels, starting at the max tile size, and going up to the current // tile size TransformedBitmap downsampledImage = JpegDecoder.DownsampleJpeg( imageStream, Math.Ceiling(width * levelSize / maxTileSize), Math.Ceiling(height * levelSize / maxTileSize)); // Copy the pixels to a buffer and then write them to the // appropriate region on the output image. int stride = (downsampledImage.PixelWidth * downsampledImage.Format.BitsPerPixel + 7) / 8; byte[] buffer = new byte[stride * downsampledImage.PixelHeight]; downsampledImage.CopyPixels(buffer, stride, 0); Int32Rect outputRect = new Int32Rect(locX, locY, downsampledImage.PixelWidth, downsampledImage.PixelHeight); outputBitmap.WritePixels(outputRect, buffer, stride, 0); } else { // We should render the image, but we're done with our list. // So, exit both loops. x = imagePerSide; y = imagePerSide; } } else { // Since n is monotonic wrt y, we know y has gone too far down, so // we can reset it. y = imagePerSide; } } } } // Write the output BitmapFrame outputFrame = BitmapFrame.Create(outputBitmap); BitmapEncoder encoder = new JpegBitmapEncoder(); encoder.Frames.Add(outputFrame); encoder.Save(output); } ///  /// Converts an x and y to a Morton number ///  /// x location to convert. /// y location to convert. /// Returns the morton number which corresponds to the /// given x and y coordinates. private static int XYToMorton(int x, int y) { const uint BITS_PER_BYTE = 8; const uint BIT_PAIRS = sizeof(int) * BITS_PER_BYTE / 2; int morton = 0; for (int i = 0; i < BIT_PAIRS; i++) { morton |= (x & 1) << (i * 2); morton |= (y & 1) <>= 1; y >>= 1; } return morton; } } } 

C#:

 yield return scriptRef 

VB.NET:

 Return New List(Of ScriptReference) From {scriptRef} 

空无一人。 期。 除非您要编写自己的状态机,否则没有快速解决方法。 请参阅博客文章VB.NET的“收益率回报”

对于那些关心实际生成的人(是的,我喜欢C#预编译器和编译器:)):

尝试编译它并使用.NET Reflector或其他东西查看生成的代码:

 class Program { static void Main(string[] args) { var foo = new Foo(); foreach(var result in foo.Bar()) { Console.WriteLine(result); } Console.ReadLine(); } } class Foo { public IEnumerable Bar() { const char start = 'a'; for(int x = 0;x < 26;x++) { yield return (char)(start + x); } } } 

我不会复制结果,这是巨大的。 但是看一看,你会发现解决起来并不简单。

VB中的yield没有确切的重复。 您最好的选择是创建正在yield的集合并将整个集合返回给调用代码进行迭代。 这与您给出的代码并不完全相同,但它应该具有相同的整体效果。 yield本质上只是一个语法糖,用于将一个集合的部分返回到一个foreach循环,一次一个优化运行时间并允许早期突破(如果你决定不需要枚举所有内容)。

带有yield return / yield break语句的代码块称为迭代器 。 VB中不存在此function。 当然,可以“翻译”该代码,但它并不是非常简单……您需要创建一个实现IEnumerator(Of Integer)的自定义类来重现完全相同的行为:

  • 使用原始函数的参数对其进行初始化
  • 通过将循环变量存储在私有字段中,在MoveNext方法中实现“循环”逻辑。 此方法还应设置一个字段来保存当前值(原始函数中的n
  • Current属性返回当前值
  • Reset方法中重置循环变量
  • Dispose方法中什么也不做

这是可行的,但老实说,这是一个痛苦……

另一个更简单的选择是用结果填充List(Of Integer)并返回该列表:只需用list.Add(n)替换yield return n

没有。 但是,您可以创建一个。
创建一个迭代器类。
这样做的几个步骤:

  1. 创建一个基本上是迭代步骤的函数。 该函数应该采用每个计算所需的任何参数,并返回参数以进行下一次计算。 (为了实现yield break以及yield return,这个函数还需要能够返回一些标记结束的布尔值)
  2. 创建一个实现IEnumerator的类。 Current属性应返回最新的计算值,Reset应将所有值重置为其初始值,MoveNext函数应计算下一个值,如果计算函数返回false,则返回false本身。

要获得额外的功劳,请使该类具有通用性,并且能够使用委托给它的任何函数。
你可以简化这一点并使MoveNext成为计算函数本身,但这样就可以很容易地从同一个类实现中创建不同的迭代器。

在VB.NET中没有等效的yield return ,但它可以被模拟。

请参阅VB.NET中的 Stack Overflow问题产生及其答案。

也许Visual Studio杂志文章在VB Now中使用Iterators会有所帮助。