C++/CLI
Nelle ultime settimane mi sono imbattuto in tre features di Visual C++ Express. Sono caratteristiche poco "appariscenti", sulle quali sarebbe sprecato fare marketing, ma che si sono rivelate particolarmente utili.
1. E' possibile aprire vecchi progetti per Visual C++ 6. La procedura di conversione è pressochè indolore. Naturalmente, a causa degli allineamenti agli standard C++, è possibile che il nuovo compilatore generi messaggi di avviso, indicando che vengono usati costrutti sintattici deprecati.
2. Durante l'apertura di un file, l'editor rileva automaticamente se la convenzione di terminazione linea è consistente e, in caso contrario, propone un allineamento con lo standard per Windows, Unix o Macintosh.
3. Per impostazione definita i file...
Vediamo il seguente codice. Viene definito un
reference type (typeid = Person), con un metodo publico,
ReadMessage. Al suo interno viene utilizzato in tre modi diversi un
oggetto di tipo System::IO::StreamReader, classe che implementa
System::IDisposable.
public ref class Person{public: Person (String^ name, String^ surname) { } void ReadMessage (String^ path) { Stream^ stream = (Person::typeid)->Assembly->GetManifestResourceStream (path);#ifdef MANUAL_DETERMINISTIC_CLEANUP // I manually call the distructor. StreamReader^ reader = gcnew StreamReader (stream); Console::WriteLine (reader->ReadLine ()); delete reader;#endif#ifdef AUTOMATIC_CLEANUP // Garabace collector will call the dispose methods before finalizing the reader. StreamReader^ reader = gcnew StreamReader (stream); Console::WriteLine (reader->ReadLine ());#endif#ifdef AUTOMATIC_DETERMINISTIC_CLEANUP // The compiler automatic inserts a method call to dispose. // The reference type instance has value semantic in this context. StreamReader reader (stream); Console::WriteLine (reader.ReadLine ());#endif }};
Decompiliamo con Reflector e
vediamo come apparirebbe, nei diversi casi, il metodo
ReadMessage se fosse scritto in C#.
Nel primo caso reader è stato dichiarato come un handle, al
quale abbiamo è stato assegnato un oggetto allocato sul managed
heap tramite l'operatore gcnew
. Dopo essere stato utilizzato, l'oggetto viene "distrutto" con l'operatore
delete. Tale
operatore viene sostanzialmente ...
Se state usando Visual C++ 2005, vi sarete probabilmente accorti che l'ambiente non è ancora del tutto completo. Esistono alcune limitazioni nella gestione del progetto (file di risorsa, file di soluzione, etc.). Non so se queste rimarranno limitazioni del prodotto Express definitivo, ad ogni modo potete ovviare a questi problemi scrivendo manualmente il file di progetto e vcbuild.exe per compilarlo. Qui potete trovate lo schema XML:
http://msdn2.microsoft.com/library/y4sy8216(en-us,vs.80).aspx
Il designer è decisamente migliorato, tuttavia, a mio parere, genera un pessimo codice. Sarebbe stato importante, per lo meno, che separasse le implementazioni dei metodi (in particolare, del costruttore e dei delegati che gestiscono gli eventi) dalla...
Ho scritto un file per il syntax highlighting di Code Snippet
Editor destinato al nuovo linguaggio C++/CLI.
Come vi sembrano i colori? Sicuramente non è perfetto ma per iniziare può
andare bene.
A proposito... se non conoscete le novita del nuovo linguaggio che sarà
rilasciato con Whidbey, date un'occhiata al codice. Presto scriverò un articolo
in merito...
Credo che il mio rapporto con C# stia per finire... dopo soli 3
mesi...
Ecco un piccolo esempio (non mostra proprio tutti tutti i costrutti... ma non
volevo esagerare).
PS Scusate, lo riposto scrollabile perchè mi sembrava un po' da cafoni
occupare tutta la pagina dei nuovi post
#using <mscorlib.dll>#using <System.dll>#pragma managedusing namespace System;namespace Example { /* Customer data. * Inherits from System::ValueType. */public value struct CustomerKey: IComparable<CustomerKey^>{ public: CustomerKey (String^ firstName, String^ lastName): FirstName (firstName), LastName (lastName) { } String^ FirstName; String^ LastName; bool Equals (CustomerKey^ key) override { bool firstNameResult = this->FirstName->Equals (key->FirstName); bool lastNameResult = this->LastName->Equals (key->LastName); return (firstNameResult && lastNameResult); } int CompareTo (CustomerKey^ key) override { return Equals (key); } };/* Customer. * Inherits from System::Object. */public ref class Customer{private: initonly CustomerKey key_; public: Customer (CustomerKey % key) { key_ = key; } Customer (String^ firstName, String^ lastName) { if (firstName == nullptr) throw gcnew ArgumentNullException (); if (lastName == nullptr) throw gcnew ArgumentNullException (); key_ = CustomerKey (firstName, lastName); } property CustomerKey^ Key { CustomerKey^ get () { return key_; } } property String^ FirstName { String^ get () { return key_.FirstName; } } property String^ LastName { String^ get () { return key_.LastName; } } String^ ToString () override { String^ s = key_.FirstName; return s; }};typedef System::Collections::Generic:ictionary<CustomerKey^, Customer^> CustomerDictionary;typedef System:iagnostics:ebug Debug;public ref class CustomerContainer { CustomerDictionary^ customers_;public: CustomerContainer () { customers_ = gcnew CustomerDictionary (); } void Insert (String^ firstName, String^ lastName) { try { Customer^ customer = gcnew Customer (firstName, lastName); customers_->Add (customer->Key, customer); Debug::WriteLine ("Inserted: %s", customer->ToString ()); } catch (Exception^ exception) { Debug::WriteLine (exception->Message); throw; } }};}using namespace Example;/* Entry point of the application. * It should be in the default namespace! */int main () { String^ helloWorld = "Hello world!"; CustomerContainer^ container = gcnew CustomerContainer (); container->Insert ("Andrea", "Sansottera"); return 0;}