Invocare metodi Lua da C# con i Delegate

Nel precedente messaggio abbiamo visto come recuperare un oggetto LuaFunction, contenente il riferimento a una funzione definita in uno script Lua, sfruttando il metodo GetFunction. Lo stesso metodo però ha un overload abbastanza interessante che offre la possibilità di recuperare un delegate, con il vantaggio di poterci quindi integrare meglio all'interno del framework .NET. Vediamo un esempio:

1 using System; 2 using LuaInterface; 3 4 namespace NRK 5 { 6 public delegate double AddDelegate(double a, double b); 7 8 class Application 9 { 10 static void Main(string[] args) 11 { 12 Lua lua = new Lua(); 13 14 lua.DoString(@" 15 function add(x, y) 16 return x + y 17 end 18 "); 19 20 AddDelegate add = lua.GetFunction(typeof(AddDelegate), "add") as AddDelegate; 21 22 if (IsDefinedInLua(add)) 23 { 24 double res = add(5.3, 3.2); 25 Console.WriteLine(String.Format("Il risultato è: {0}", res)); 26 } 27 } 28 29 static bool IsDefinedInLua(Delegate delegateOfFunction) 30 { 31 if (delegateOfFunction.Target is LuaDelegate) 32 return (delegateOfFunction.Target as LuaDelegate).function != null; 33 34 return false; 35 } 36 } 37 }

Come al solito analizziamo il codice:

  • riga 6: definiamo il delegate che verrà utilizzato per invocare la nostra funzione in Lua. Purtroppo non è possibile definire il delegate utilizzando una lista variabile di argomenti dal momento che LuaInterface non lo supporta, quindi questo tipo di definizione non è valido e a runtime lancia un'eccezione:
    // non funzionerà a runtime... public delegate double AddDelegate(params double[] args);
  • riga 20: l'overload di GetFunction prende come parametri un System.Type per poter generare il delegate del tipo corretto e il nome della funzione in Lua da associargli. Come potete vedere la sintassi è un po' verbosa, usando i generics sarebbe possibile rimuovere almeno un AddDelegate e la chiamata a typeof, per fare ciò dovremmo definire un metodo di utilità come vedremo più avanti.
  • riga 22: il metodo IsDefinedInLua che qui abbiamo utilizzato e che alla riga 29 abbiamo definito è un helper che ci permette di capire se internamente il nostro delegate punta a una funzione Lua effettivamente definita oppure no, questo per evitare di incappare in una NullReferenceException nel caso nel codice Lua non sia esistente la funzione add. La mia impressione è che probabilmente sarebbe stato meglio se in LuaInterface avessero definito un tipo che identificasse chiaramente il puntamento a una funzione inesistente all'interno di una istanza di LuaDelegate (chessò, un tipo NullLuaFunction per esempio) anziché utilizzare direttamente null, in questo modo avrebbero evitato ai programmatori di incappare in eccezioni di questo tipo a runtime o di effettuare costantemente dei controlli per evitarle.

Facendo un passo indietro, prima abbiamo notato come l'overload di GetFunction utilizzato in questa occasione abbia in realtà una sintassi abbastanza pesante, vediamo quindi come ridurne la verbosità sfruttando i generics:

static T CreateDelegate<T>(Lua lua, String function) where T : class { Type delegateType = typeof(T); if (!delegateType.IsSubclassOf(typeof(Delegate))) throw new ArgumentException("T must be derived from System.Delegate"); return lua.GetFunction(delegateType, function) as T; } // Esempio di utilizzo: // AddDelegate add = CreateDelegate<AddDelegate>(lua, "add");

Integreremo più avanti questo metodo nel nostro codice, però possiamo già fare qualche considerazione:

  • purtroppo i delegate e le classi che ne derivano non possono essere usati come constraint per i generic. Può sembrare brutto ma in realtà esiste un buon motivo per questa limitazione, riprenderò l'argomento in un breve con un messaggio dedicato che vi illustro in questo messaggio.
  • il fatto che non si possano usare i delegate come constraint ci obbliga a fare un minimo di controllo giusto per essere sicuri e, nel caso, indicare la retta via, per cui controlliamo che il tipo T sia effettivamente derivante da System.Delegate e sia quindi consumabile da GetFunction.
  • usiamo class come constraint per poter utilizzare l'operatore as ed effettuare quindi un cast dal tipo base System.Delegate (resituito da GetFunction) al tipo specificato da T.
  • avendo a disposizione le novità di C# 3.0 sarebbe stato possibile utilizzare gli extension method per poter "attaccare" direttamente a LuaInterface.Lua il metodo generico CreateDelegate<T>, sarebbe stato sicuramente tutto molto più pulito.

Nei prossimi messaggi cominceremo a capire meglio l'utilità di utilizzare un delegate piuttosto che un oggetto LuaFunction per invocare i metodi definiti in Lua.


Puoi scrivere un commento oppure inviare un trackback dal tuo sito.

1 commento a “Invocare metodi Lua da C# con i Delegate”

  1. download

    clorophilla.blog

Lascia un commento

Puoi utilizzare i seguenti tag XHTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>