30. Interop .NET
MALDA offre il supporto nativo al caricamento e all'uso di librerie .NET esterne, e così consente di accedere al vasto ecosistema .NET: pacchetti NuGet, class library personalizzate e API del framework. I programmi MALDA possono riusare codice .NET esistente senza riscriverlo.
30.1 Tipi già nel runtime
Non ti serve una DLL personalizzata per i tipi BCL di base. Passa il nome completamente qualificato a dotnetNew o getDotNetType. I tipi generici usano l'arietà con backtick: List`1 significa List<T> con un parametro di tipo.
var sb = dotnetNew("System.Text.StringBuilder");
sb.Append("hello");
sb.Append(" ");
sb.Append("MALDA");
print(sb.ToString());
30.2 Caricamento degli assembly .NET
loadAssembly(pathOrName)
Carica un assembly .NET da un path di file o per nome di assembly.
Sintassi
var asm = loadAssembly("path/to/library.dll");
var asm = loadAssembly("System.Data"); // Load by assembly name
Parametri
pathOrName(string): Un path di file a un .dll (assoluto o relativo) oppure un nome di assembly
Valore restituito
object: Un oggetto assembly da usare congetDotNetType()
Comportamento
- Se l'argomento è un path radicato (es.
C:\path\to\file.dll) o termina con.dll, viene trattato come path di file - Altrimenti viene trattato come nome di assembly e caricato con
Assembly.Load() - Solleva un'eccezione se l'assembly non può essere trovato o caricato
Esempio
// Load from file path
var customLib = loadAssembly("C:\\MyLibs\\MyLibrary.dll");
// Load by assembly name (from GAC or already loaded)
var systemData = loadAssembly("System.Data");
30.3 Ottenere i tipi .NET
getDotNetType(assembly, typeName) or getDotNetType(fullTypeName)
Recupera un tipo .NET da un assembly o da tutti gli assembly caricati.
Sintassi
// From a specific assembly
var type = getDotNetType(asm, "MyNamespace.MyClass");
// From any loaded assembly (searches all loaded assemblies)
var type = getDotNetType("System.Collections.Generic.List`1");
Parametri
- Opzione 1:
assembly(object): Oggetto assembly restituito daloadAssembly() - Opzione 1:
typeName(string): Nome di tipo completamente qualificato (namespace + nome della classe) - Opzione 2:
fullTypeName(string): Nome di tipo completamente qualificato (cerca in tutti gli assembly caricati)
Valore restituito
object: Un type handle da usare condotnetNew()
Esempio
var asm = loadAssembly("MyLibrary.dll");
var myClassType = getDotNetType(asm, "MyLibrary.MyClass");
// Or search all loaded assemblies
var listType = getDotNetType("System.Collections.Generic.List`1");
List`1 per List<T>). Il numero dopo il backtick indica il numero di parametri di tipo.
30.4 Creare oggetti .NET
dotnetNew(typeOrTypeName, ...ctorArgs)
Crea una nuova istanza di un tipo .NET.
Sintassi
var obj = dotnetNew(typeHandle);
var obj = dotnetNew(typeHandle, arg1, arg2); // With constructor arguments
var obj = dotnetNew("System.Text.StringBuilder"); // Direct from type name
Parametri
typeOrTypeName(object o string): Un type handle dagetDotNetType()oppure una stringa con il nome di tipo completamente qualificato...ctorArgs(variadico): Argomenti del costruttore (opzionale)
Valore restituito
object: Un'istanza di oggetto .NET su cui puoi chiamare metodi e accedere alle proprietà
Esempio
// Using type handle
var type = getDotNetType(asm, "MyLibrary.MyClass");
var instance = dotnetNew(type);
// With constructor arguments
var instance2 = dotnetNew(type, "arg1", 42);
// Direct from type name
var sb = dotnetNew("System.Text.StringBuilder");
30.5 Usare gli oggetti .NET
Una volta creata un'istanza .NET, puoi:
- Chiamare metodi di istanza:
obj.MethodName(arg1, arg2) - Accedere alle proprietà:
obj.PropertyName(get) eobj.PropertyName = value(set) - Chiamare metodi statici: Usa
getDotNetType()per ottenere il tipo, poi chiama i metodi statici sul type handle
Conversione di tipo
MALDA converte automaticamente tra tipi MALDA e tipi .NET:
- Interi MALDA →
int,long,short,byte,double,float - Float MALDA →
double,float,decimal - Boolean MALDA →
bool - Stringhe MALDA →
string - Array MALDA → array .NET o
object[] - Oggetti .NET → wrappati come
DotNetObjectInstanceper l'accesso a metodi e proprietà
Esempio
// Load assembly and create instance
var asm = loadAssembly("C:\\path\\to\\TestLib.dll");
var fooType = getDotNetType(asm, "TestLib.Foo");
var foo = dotnetNew(fooType);
// Call instance method
var sum = foo.Add(2, 3);
print("2 + 3 = " + string(sum));
// Access and set properties
foo.Name = "from MALDA";
print("Foo.Name = " + foo.Name);
// Use a BCL type already loaded (no custom DLL)
var sb = dotnetNew("System.Text.StringBuilder");
sb.Append("item1");
sb.Append("item2");
print("Length: " + string(sb.Length));
Callback native
createNativeCallback(fn) wrappa una funzione MALDA così da poterla passare a codice .NET che si aspetta un delegate, per esempio un event handler o un parametro di callback su un oggetto di interop. L'argomento deve essere un valore funzione; qualsiasi altro tipo solleva un errore.
var callback = createNativeCallback((value) => {
print("called back with " + value);
});
nativeObject.onChanged(callback);
30.6 Usare i pacchetti NuGet
Per usare pacchetti NuGet in MALDA:
- Crea una .NET Class Library che referenzia il pacchetto NuGet
- Compila la library per generare un file .dll
- Carica l'assembly in MALDA con
loadAssembly() - Usa i tipi del pacchetto tramite
getDotNetType()edotnetNew()
Flusso di lavoro di esempio
// Load a library that uses a NuGet package (e.g., Newtonsoft.Json)
var jsonLib = loadAssembly("C:\\MyLibs\\JsonHelper.dll");
var jsonHelperType = getDotNetType(jsonLib, "JsonHelper.JsonProcessor");
var processor = dotnetNew(jsonHelperType);
// Use the library
var result = processor.ProcessJson(jsonString);
30.7 Esempio completo
// Example: Using a custom .NET library
var asmPath = "C:\\MyLibraries\\MathUtils.dll";
var asm = loadAssembly(asmPath);
// Get a type from the library
var calculatorType = getDotNetType(asm, "MathUtils.Calculator");
var calc = dotnetNew(calculatorType);
// Use the calculator
var result = calc.Add(10, 20);
print("10 + 20 = " + string(result));
// Access properties
calc.Precision = 5;
print("Precision set to: " + string(calc.Precision));
30.8 Note di implementazione
- Caricamento degli assembly: Usa
Assembly.LoadFrom()per i path di file eAssembly.Load()per i nomi di assembly - Risoluzione dei tipi: Cerca negli assembly caricati se il tipo non si trova nell'assembly specificato
- Risoluzione degli overload: Seleziona automaticamente l'overload del metodo che meglio corrisponde, in base al numero di parametri e alla compatibilità dei tipi
- Gestione degli errori: Solleva eccezioni con messaggi descrittivi se assembly, tipi o metodi non possono essere trovati
- Type safety: Il controllo dei tipi a runtime garantisce che chiamate di metodo e accessi alle proprietà siano validi
30.9 Casi d'uso
- Riusare librerie .NET esistenti: Usare pacchetti NuGet consolidati senza riscrivere codice
- Logica di business personalizzata: Creare librerie .NET per operazioni complesse e chiamarle da MALDA
- Codice critico per le prestazioni: Scrivere il codice sensibile alle prestazioni in C# e chiamarlo da MALDA
- Integrazione con il framework: Accedere alle API .NET Framework (es.
System.IO,System.Net,System.Data) - Integrazioni di terze parti: Usare SDK .NET per servizi esterni (database, API, ecc.)
Vedi anche
- 12. Input/Output — console, file, path, ambiente
- 11. Classi e oggetti - Creare e usare classi MALDA
- 33. Esempi - Esempi di codice completi