Ieri ho passato un po’ di tempo insieme a Marco Amendola (via Skype) a studiare le trasformazioni di XAML, per capire se fosse eventualmente possibile definire una trasformazione custom, diversa da quelle predefinite.
Senza entrare nel dettaglio, visto che sto scrivendo un articolo sull’argomento che spero di riuscire a completare e pubblicare a breve, l’occasione è stata utile per provare ad utilizzare l’ultima versione di .NET Reflector con le librerie WinRT.
L’idea era di poter scrivere un codice del tipo:
Guardando nella classe Transform non si trova nulla di utile (anzi, è proprio vuota), ma la classe base GeneralTransform ha invece un paio di metodi di cui si può fare l’override.
Peccato che la Dependency Property RenderTransform voglia una istanza di tipo Transform, e non una General Transform, perché MyTransform: GeneralTransform compila senza problemi mentre MyTransform: Transform no.
A prima vista la cosa appare strana, perché con .NET Reflector si ha:
La classe è pubblica, il costruttore non è esplicitamente dichiarato, quindi dovrebbe esserci quello di default, che secondo i dettami C# è pubblico (è un po’ più complicato di cosi, ma ai fini di questa storia, passatemela senza sottilizzare sulle diverse casistiche che darebbero visibilità diverse).
Ma non c’è verso, il compilatore rifiuta di compilare, avvertendomi che manca il costruttore della classe base.
E qui casca l’asino (che sarei io).
Perché dopo aver rotto le scatole a destra e manca, prima Vito e poi Raf mi danno la soluzione: stiamo parlando di una libreria WinRT, mica di codice managed!
E se è pur vero che grazie a WinRT io “vedo” le librerie di sistema come se fossero state scritte in C#, è altrettanto vero che le librerie sono roba COM. E da quello che ho capito, in COM se non dichiari il costruttore, la classe non ce l’ha. (vedi UPDATE2)
Però, dico io, anche se non posso ereditare da Transform, posso sempre crearne un’istanza in C#. E com’è possibile visto che non ha costruttore? (Vedi UPDATE2)
E qui ricasca l’asino (che sarei sempre io).
Perché WinRT è proprio bravo a nascondere questi dettagli, e senza che io (semplice sviluppatore C#) ne sappia nulla, quando chiedo la costruzione di una istanza di Transform, lui utilizza un oggetto factory associato al cui interno c’è la chiamata alla funzione COM “CoCreateIstance” che crea l’istanza di Transform (in effetti non crea proprio l’istanza della classe, perché COM è procedurale e non object oriented, ma per capirlo bisogna masticare un minimo di COM, vedi il link alla fine).
Happy ending
Grazie alla mia testarda “ciucagine”, e all’aiuto dei miei disponibilissimi amici, posso dire di aver meglio compreso il ruolo di WinRT come “wrapper” tra il mondo unmanaged delle librerie di sistema e i programmi scritti con linguaggi object oriented come C#, ideati sin dall’inizio per lavorare in un ambiente managed (il buon vecchio .NET Framework, per intenderci).
Sentiti ringraziamenti vanno, in ordine sparso, a : Marco, Gian Maria, Lorenzo, Vito e Raf.
Per chi vuole rispolverare vecchi concetti o fare un rapido tuffo nel mondo COM, consiglio vivamente la lettura di questo ottimo e succinto articolo (del 27 luglio 2000 !): http://www.codeproject.com/Articles/633/Introduction-to-COM-What-It-Is-and-How-to-Use-It
Happy coding!
UPDATE: Questo post è da prendere con le molle, perché di COM so davvero poco e il fatto che una classe COM non abbia il costruttore è discutibile, e forse errata. A breve seguirà un aggiornamento…
UPDATE2: In effetti la questione è più semplice: il costruttore c’è (perché il costruttore c’è sempre) ma evidentemente è dichiarato come private o più probabilmente come internal. E in un WinRT component ciò che non è pubblico o protected non appare nel file WinMD del suo assemby.
Infatti, a differenza dei file WinMD degli assembly .NET, i file WinMD di un assembly WinRT non contengono codice ma solo metadati, utilizzati per le projection, ovvero quel particolare meccanismo di “traduzione” che consente ai diversi linguaggi (C#, VB.NET e Javascript) di vedere le WinRT API come “native” di ciascun linguaggio. E’ dunque ovvio che in quest’ottica i metadati siano presenti solo per gli elementi utilizzabili “da fuori”.
Altri link utili:
- WinRT (Wikipedia)
- Namespaces and Type Visibility (C++/CX )