Lokalisierung in .NET 2.0
Probieren Sie zur Veranschaung einmal folgendes Beispiel in Visual Studio 2003: Ziehen Sie einen Button auf eine Form und schauen Sie sich den in der InitializeComponent()-Methode generierten Code an. Sie werden feststellen, dass lediglich 4 Eigenschaften zugewiesen wurden, nämlich extakt die, die keine Standardwerte enthielten. Wechseln Sie nun wieder in den Designer und setzen Sie die Localizable-Eigenschaft der Form auf true. Wenn Sie sich jetzt erneut den Code anschauen, werden Sie feststellen, dass diesmal für 20 Eigenschaften Code generiert wurde, unabhängig davon, ob diese mit ihren jeweiligen Standardwerten belegt sind. Schauen wir uns das mal aus der Nähe an.
Eine Komponente kann die Code Generierung unter anderem durch die Attribute DefaultValue und Localizable steuern. Während Erstere den Standardwert einer Eigenschaft angibt, bestimmt Letztere, ob diese lokalisierbar ist. Das folgende Beispiel verdeutlicht dies:
public class MyControl : Control
{
private string m_myData = string.Empty;
[DefaultValue("")]
[Localizable(true)]
public string MyData
{
get { return m_myData; }
set { m_myData = value; }
}
}
Das DefaultValue-Attribut gibt hierbei den Standardwert der Eigenschaft an. Auf diese Weise wird nur dann Code erzeugt, wenn die jeweilige Instanz des Controls einen abweichenden Wert für die MyData-Eigenschaft enthält. Zusätzlich wurde die Eigenschaft mit dem Localizable-Attribut versehen. Dies bewirkt, dass im Falle einer lokalisierten Form, der Wert der Eigenschaft aus den Ressourcen ermittelt wird.
Wenn Sie dieses Control nun auf eine nicht lokalisierte Form ziehen und die MyData-Eigenschaft ändern, wird der folgende Code in der InitializeComponent()-Methode erzeugt:
this.myControl1.MyData = "123";
Enthält die Eigenschaft jedoch den Standardwert, so wird eine explizite Zuweisung des Wertes überflüssig und daher auch kein Code erzeugt.
Handelt es sich jedoch um eine lokaliserte Form, so findet diese Prüfung nicht statt, sondern es wird in jedem Fall Code nach folgendendem Stickmuster erzeugt:
System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(Form1));
…
this.myControl1.MyData = resources.GetString("myControl1.MyData");
Dieses Verhalten wurde so implementiert, da es sein kann, dass eine Eigenschaft in einer Sprache gesetzt und in einer anderen Sprache nicht gesetzt sein kann. Dies ergibt zwar durchaus Sinn, führt jedoch zu einem weitaus höheren Code-Aufkommen. Zudem müssen alle Werte stets aus den Ressourcen ermittelt werden, was weitaus langsamer ist, als würden sie direkt zugewiesen. In der Praxis ist es jedoch so, dass eine Eigenschaft meist in allen Sprachen gesetzt wird und somit die Kosten den Nutzen nicht aufwiegen.
Daher wurde das Lokalisierungskonzept in .NET 2.0 grundlegend geändert. So besteht das Prinzip des Localizable-Attributs zwar fort, der generierte Code ist nun jedoch ein anderer.
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
resources.ApplyResources(this.myControl1, "myControl1");
this.myControl1.Name = "myControl1";
Wie Sie sehen, wurde hierbei lediglich für die Name-Eigenschaft Code erzeugt. Alle weiteren lokalisierbaren Eigenschaften werden über die ApplyResources()-Methode der ComponentResourceManager-Klasse zugewiesen. Während der Code-Generierung werden die entsprechenden Werte in der Ressource-Datei gespeichert und hierbei die Standardwerte berücksichtigt. Zur Laufzeit analysiert ApplyResources() nun per Reflection die Komponente und liest die Werte aus den jeweiligen Sprach-Ressourcen.
Wieder so eine kleine Änderung, die in komplexen Projekten jedoch einen erheblichen Performance-Vorteil bringt.