Warum C# nicht im luftleeren Raum existiert und wie es funktioniert
\n\nAls ich vor etwa zehn Jahren mit C# zu arbeiten begann, schien mir .NET ein autarkes Universum zu sein. Bibliotheken, Frameworks, Datenbanken – alles griffbereit. Aber dann kam die Aufgabe: Ich musste eine alte C++-Bibliothek zur Signalverarbeitung verwenden. Und da wurde mir klar – Integration von C# mit anderen Sprachen ist kein Luxus, sondern eine Notwendigkeit für jedes ernsthafte Projekt.
\n\nHeute ist C# eine plattformübergreifende Sprache mit einem reichhaltigen Ökosystem, aber sie kann nicht alles. Manchmal muss man ein Python-Skript für maschinelles Lernen ausführen, manchmal eine native Funktion aus Rust für maximale Leistung aufrufen, und manchmal eine JavaScript-Engine für die dynamische UI-Generierung einbetten. Die gute Nachricht: C# kann mit fast allen Sprachen zusammenarbeiten.
\n\nIn diesem Artikel zeige ich reale Szenarien der Interaktion von C# mit anderen Sprachen mit funktionierendem Code, Benchmarks und Fallstricken. Los geht's!
\n\nP/Invoke: Der Klassiker für C und C++
\n\nPlatform Invocation Services (P/Invoke) ist der integrierte Mechanismus von .NET zum Aufrufen von Funktionen aus nativen DLLs. Er existiert seit der ersten Version von .NET und ist nach wie vor der schnellste Weg zur Integration mit C/C++-Code.
\n\nBasisbeispiel: Aufruf einer Funktion aus C
\n\nAngenommen, wir haben eine native Bibliothek math_helper.dll mit der Funktion:
// math_helper.h\nextern "C" __declspec(dllexport) double calculate_power(double base, int exp);\n\nIn C# binden wir sie wie folgt ein:
\n\nusing System.Runtime.InteropServices;\n\npublic class NativeMath\n{\n [DllImport("math_helper.dll", CallingConvention = CallingConvention.Cdecl)]\n public static extern double calculate_power(double base, int exp);\n}\n\n// Verwendung\ndouble result = NativeMath.calculate_power(2.0, 10);\nConsole.WriteLine($"2^10 = {result}"); // 1024\n\nWichtige Punkte bei P/Invoke C#:
\n- \n
- Geben Sie immer
CallingConventionan – meistensCdecloderStdCall. \n - Verwenden Sie für Zeichenfolgen
MarshalAs(UnmanagedType.LPStr)oderLPWStr. \n - Übergeben Sie Strukturen per Referenz mit
refoderout. \n
P/Invoke verursacht nur minimale Overhead – buchstäblich einige Nanosekunden pro Aufruf. Wenn Sie C# mit C++ integrieren müssen für hochlastige Berechnungen – das ist Ihre Wahl.
\n\nC++/CLI: Die Brücke zwischen den Welten
\n\nC++/CLI ist eine Erweiterung von Visual C++, die es ermöglicht, Code zu schreiben, der sowohl in der verwalteten (.NET) als auch in der nicht verwalteten Umgebung läuft. Es ist keine separate Sprache, sondern ein Hybrid, der oft zum Erstellen von Wrappern für C++-Bibliotheken verwendet wird.
\n\nBeispiel eines Wrappers für OpenCV
\n\nAngenommen, wir haben eine C++-Funktion, die ein Bild verarbeitet:
\n\n// NativeImageProcessor.h\n#pragma once\npublic ref class ImageProcessor\n{\npublic:\n static System::Drawing::Bitmap^ ApplyFilter(System::Drawing::Bitmap^ bmp);\n};\n\nIntern rufen wir natives OpenCV auf und geben nach außen ein verwaltetes Bitmap zurück. Aus C# verwenden wir es wie eine normale .NET-Bibliothek:
using ImageProcessorLib;\n\nvar img = new Bitmap("photo.jpg");\nvar processed = ImageProcessor.ApplyFilter(img);\nprocessed.Save("filtered.jpg");\n\nC++/CLI-Integration bietet vollständige Kontrolle über den Speicher und vermeidet Marshalling. Nachteil: Der Code wird plattformabhängig und schwieriger zu debuggen.
\n\nPython.NET: Python aus C# aufrufen
\n\nPython ist der König von Data Science und maschinellem Lernen. Und wenn Ihr C#-Projekt beispielsweise das Ausführen eines neuronalen Netzes mit PyTorch oder die Textverarbeitung mit spaCy erfordert, dann ist Python aus C# aufrufen über Python.NET genau das Richtige.
\n\nInstallation und erstes Beispiel
\n\nPaket installieren:
\n\ndotnet add package Python.Runtime.NETStandard