使用下面的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
{
/// <summary>
/// Tile Builder class
/// </summary>
public static class TileBuilder
{
/// <summary>
/// Specifies which images are required in the images array used in CreateTile
/// according to the Morton fractal pattern used by Seadragon.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
/// <param name="imageCount">Number of images in the full set.</param>
/// <param name="level">The level to which each image will be downsampled.</param>
/// <param name="row">The row number which specifies what images to render.</param>
/// <param name="column">The row number which specifies what images to render.</param>
/// <param name="tileSize">The size of the tile to return.</param>
public static IEnumerable<int> 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;
}
}
}
}
/// <summary>
/// Create a tile for a collection according to the Morton fractal
/// pattern used by Seadragon.
/// </summary>
/// <remarks>
/// See GetTileIds for more information.
/// </remarks>
/// <param name="imageCount">The total number of images in the collection.</param>
/// <param name="images">Jpeg images to render on this tile.
/// If this is null, a blank tile will be returned.
/// See GetTileIds remarks for more information.</param>
/// <param name="level">The level to which each image will be downsampled.</param>
/// <param name="row">The row number which specifies what images to render.</param>
/// <param name="column">The row number which specifies what images to render.</param>
/// <param name="tileSize">The size of the tile to return.</param>
/// <param name="output">The stream to use to output the result.</param>
public static void CreateTile(
int imageCount,
IEnumerable<ImageBag> 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<ImageBag> 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);
}
/// <summary>
/// Converts an x and y to a Morton number
/// </summary>
/// <param name="x">x location to convert.</param>
/// <param name="y">y location to convert.</param>
/// <returns>Returns the morton number which corresponds to the
/// given x and y coordinates.</returns>
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) << ((i * 2) + 1);
x >>= 1;
y >>= 1;
}
return morton;
}
}
}
答案 0 :(得分:16)
没有。期。除非您要编写自己的状态机,否则没有快速解决方法。请参阅博客文章 VB.NET's "yield return" 。
对于那些关心实际生成内容的人(是的,我喜欢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<char> Bar()
{
const char start = 'a';
for(int x = 0;x < 26;x++)
{
yield return (char)(start + x);
}
}
}
我不会复制结果,这是巨大的。但是看一看,你会发现解决起来并不简单。
答案 1 :(得分:3)
VB中没有yield
的完全重复。您最好的选择是创建正在yield
的集合并将整个集合返回给调用代码进行迭代。这与您给出的代码并不完全相同,但它应该具有相同的整体效果。 yield
基本上只是语法糖,用于一次一个地将一个集合的部分返回到foreach
循环,以优化运行时间并允许早期突破(如果您决定不需要枚举所有内容)毕竟)。
答案 2 :(得分:3)
包含yield return
/ yield break
语句的代码块称为iterator。 VB中不存在此功能。当然,可以“翻译”该代码,但它不是非常简单......您需要创建一个实现IEnumerator(Of Integer)
的自定义类来重现完全相同的行为:
MoveNext
方法中实现“循环”逻辑。此方法还应设置一个字段以保存当前值(原始函数中的n
)Current
属性Reset
方法Dispose
方法这是可行的,但老实说,这是一种痛苦......
另一种更简单的选择是使用结果填充List(Of Integer)
并返回该列表:只需将yield return n
替换为list.Add(n)
答案 3 :(得分:1)
在VB.NET中没有等同于yield return
,但它可以被模拟。
请参阅Stack Overflow问题 Yield in VB.NET 及其答案。
也许Visual Studio Magazine文章 Use Iterators in VB Now 会有所帮助。
答案 4 :(得分:1)
没有。但是,您可以创建一个 创建一个迭代器类 这样做的几个步骤:
要获得额外的功劳,请使该类具有通用性,并且能够使用委托给予它的任何功能 你可以简化这一点并使MoveNext成为计算函数本身,但这样就可以很容易地从同一个类实现中创建不同的迭代器。
答案 5 :(得分:-11)
C#:
yield return scriptRef
VB.NET:
Return New List(Of ScriptReference) From {scriptRef}