Foreach использует Утку, Вводящую
Перефразирование или бесстыдно кража от блог Krzysztof Cwalinas на этом. Более интересные мелочи, чем что-нибудь.
Для Вашего объекта поддерживать foreach, Вы не делаете , должны реализовать IEnumerable. Т.е. это не ограничение, и оно не проверяется компилятором. То, что проверяется, - то, что
, Например,
class Foo
{
public Bar GetEnumerator() { return new Bar(); }
public struct Bar
{
public bool MoveNext()
{
return false;
}
public object Current
{
get { return null; }
}
}
}
// the following complies just fine:
Foo f = new Foo();
foreach (object o in f)
{
Console.WriteLine("Krzysztof Cwalina's da man!");
}
Я бы сделал библиотеку-оболочку, используя C ++ / CLI, чтобы предоставить библиотеку C #. Это может оставить вашу библиотеку без изменений и просто обернуть ее для использования из .NET, обеспечивая лучшее из обоих вариантов.
Одна вещь, которую я нашел полезным, - это углубиться в C ++ / CLI при работе с неуправляемыми библиотеками C ++. Создайте управляемую оболочку с помощью C ++ / CLI и вызовите ее из кода C #. Управляемая оболочка может включать библиотеку (я предполагаю, что она статически связана) в свою DLL, а ссылка на проект - это все, что вам нужно для вашего кода C #.
Нет необходимости писать оболочку на C ++ / CLI. Вы можете напрямую использовать Platform Invoke из C #:
http://msdn.microsoft.com/en-us/library/aa288468%28VS.71%29.aspx
РЕДАКТИРОВАТЬ: если вы делаете это с помощью C ++ / CLI , вам нужно будет выполнять вызовы LoadLibrary и создавать указатели на функции. В C # это значительно проще. Это из учебника MSDN, связанного выше, но с моими добавленными комментариями:
class PlatformInvokeTest
{
[DllImport("msvcrt.dll")] // Specify the DLL we're importing from
public static extern int puts(string c); // This matches the signature of the DLL function. The CLR automatically marshals C++ types to C# types.
[DllImport("msvcrt.dll")]
internal static extern int _flushall();
public static void Main()
{
puts("Test");
_flushall();
}
}
РЕДАКТИРОВАТЬ: Сложные типы также могут быть маршалированы, хотя необходимо определить структуры. Этот пример взят из моего собственного кода, который вызывает GDI +. Я немного его урезал.
private static int SRCCOPY = 0x00CC0020;
private static uint BI_RGB = 0;
private static uint DIB_RGB_COLORS = 0;
[DllImport("gdi32.dll")]
private static extern bool DeleteObject(IntPtr hObject);
[StructLayout(LayoutKind.Sequential)]
private struct BITMAPINFO
{
public uint biSize;
public int biWidth;
public int biHeight;
public short biPlanes;
public short biBitCount;
public uint biCompression;
public uint biSizeImage;
public int biXPelsPerMeter;
public int biYPelsPerMeter;
public uint biClrUsed;
public uint biClrImportant;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public uint[] cols;
}
public static Bitmap Downsample(Bitmap input, int bpp)
{
Bitmap retval = null;
// We will call into this GDI functionality from C#. Our plan:
// (1) Convert our Bitmap into a GDI hbitmap (ie. copy unmanaged->managed)
// (2) Create a GDI monochrome hbitmap
// (3) Use GDI "BitBlt" function to copy from hbitmap into monochrome (as above)
// (4) Convert the monochrone hbitmap into a Bitmap (ie. copy unmanaged->managed)
IntPtr inputHandle = input.GetHbitmap();
//
// Step (2): create the monochrome bitmap.
//
BITMAPINFO bmi = new BITMAPINFO();
bmi.biSize = 40; // the size of the BITMAPHEADERINFO struct
bmi.biWidth = input.Width;
bmi.biHeight = input.Height;
bmi.biPlanes = 1;
bmi.biBitCount = (short)bpp; // 1bpp or 8bpp
bmi.biCompression = BI_RGB;
bmi.biSizeImage = (uint)(((input.Width + 7) & 0xFFFFFFF8) * input.Height / 8);
bmi.biXPelsPerMeter = 0; // not really important
bmi.biYPelsPerMeter = 0; // not really important
//
// Create the color palette.
//
uint numColors = (uint)1 << bpp; // 2 colors for 1bpp; 256 colors for 8bpp
bmi.biClrUsed = numColors;
bmi.biClrImportant = numColors;
bmi.cols = new uint[256];
if (bpp == 1)
{
bmi.cols[0] = MAKERGB(0, 0, 0);
bmi.cols[1] = MAKERGB(255, 255, 255);
}
else
{
for (int i = 0; i < numColors; i++)
{
bmi.cols[i] = MAKERGB(i, i, i);
}
}
//
// Now create the indexed bitmap
//
IntPtr bits0;
IntPtr indexedBitmapHandle = CreateDIBSection(IntPtr.Zero, ref bmi, DIB_RGB_COLORS, out bits0, IntPtr.Zero, 0);
IntPtr sourceDC = GetDC(IntPtr.Zero);
IntPtr hdc = CreateCompatibleDC(sourceDC);
IntPtr hdc0 = CreateCompatibleDC(sourceDC);
SelectObject(hdc, inputHandle);
SelectObject(hdc0, indexedBitmapHandle);
BitBlt(hdc0, 0, 0, input.Width, input.Height, hdc, 0, 0, SRCCOPY);
retval = Bitmap.FromHbitmap(indexedBitmapHandle);
//
// Dispose of the crud
//
DeleteDC(hdc);
DeleteDC(hdc0);
ReleaseDC(IntPtr.Zero, sourceDC);
DeleteObject(inputHandle);
DeleteObject(indexedBitmapHandle);
return retval;
}