Generics sind bald zu haben - aber keine Templates


Thomas Wölfer
Thomas Wölfer

10. Juli 2004


Lange dauert es nicht mehr: die .Net Version 2.0 wird definitiv im nächsten Jahr kommen. In den 'Express' Betas ist auch schon ein .Net 2.0 Beta dabei. Das wichtigste was drin sein wird: Generics.

Man kann sich Generics in .Net als sowas ähnliches vorstellen wie Templates in C++, und es gibt auch in der BCL diverse Collection-Klassen die die gängigsten Collections in Form von Generics zur Verfügung stellen. Es gibt also dann beispielsweise endlicher wieder eine generische, typensichere Listenklassen. Die Schreibweise (in C#) ist extrem ähnlich wie die Template-Schreibweise in C++:

List< int> list1; // liste aus integern
List< Command> list2;  // liste aus Objektem vom Typ 'Command'

Der Rest der Generics-Nutzung erklärt sich von selbst, wenn man einmal mit Templates in C++ gearbeitet hat. Der wichtigste Unterschied zu C++ ist der, das Generics zum Zeitpunkt der Übersetzung des Generic schon typensicher sein muss. Bei Templates muss das erst dann der Fall sein, wenn das Template konkretisiert wird. Hm .... ich glaube das braucht ein Beispiel. :-)

Die folgende Template-Klasse ist in C++ möglich:

template class<T> Foo
{
   public bool IsBar( T theT)
   {
       if( theT.HasBar()) return true;
       return false;
   }
};

Das Template geht hier davon aus, das der konkrete Typ der später für 'T' verwendet wird, auch tatsächlich eine Methode HasBar() hat. Das Template als solches wird nicht angemeckert. Erzeugt man aber später eine Konkretisierung für einen bestimmten Typ ( Foo<int> aFoo; ) der eben keine Methode HasBar() hat - dann wird diese Konkretisierung vom Compiler angemeckert. Mit anderen Worten: Das Meckern geht erst recht spät los, nämlich bei der Benutzung des Template.

Bei Generics ist das anders: Dort muss die Generic-Klasse selbst (also das Code-Fragment von oben)  bereits typensicher sein. Nachdem der Compiler aber keinerlei Aussage darüber machen kann ob 'T' nun eine HasBar() Methode hat oder nicht, kann man das obige Beispiel auch nicht übersetzen.

Will man diese Funktionalität, dann muss man dem Compiler passende Informationen mitgeben. Das geht in Form sogenannter 'Constraints', die per 'where' Keyword festgelegt werden. Angenommen man hat einen Typ namens 'IHaveBar' der eine Methode namens HasBar() hat - dann müsste man den Template - Code von oben wie folgt ändern, damit gültiger Generics-Code entsteht.

template class<T> Foo where T : IHaveBar
{
   public bool IsBar( T theT)
   {
       if( theT.HasBar()) return true;
       return false;
   }
}

Es gibt noch eine Reihe weiterer Unterschiede - aber das ist in meinen Augen der wichtigste. Letzten Endes sind Generics etwas weniger flexibel als Templates, die Implikationen von Generics sind aber deutlich leichter zu verstehen: Und typensichere Collections kann man damit auch prima bauen.