Beim Ableiten einer Klasse oder beim Implementieren eines Interface schaue ich häufig mit einem Disassembler (z.B. .NET-Reflector) nach, wie Andere bestimmte Dinge in ähnlichen Situationen gelöst haben. Aktuell versuche ich die Klasse SerialStream mit kleinen Abwandlungen zu implementieren. Eines der Probleme ist die Ausgabe von Texten, z.B. bei Fehlermeldungen (Exceptions). Die .NET-Bibliotheken greifen bei der Ausgabe von Texten auf lokalisierte Ressourcen zurück. Wenn man in eigenen Programmen diese Texte nicht alle neu erfinden will, wäre es hilfreich die bestehenden auslesen zu können.
Leider gibt es keine öffentliche Methode um diese Texte zu ermitteln. .NET benutzt hierzu die Methode GetString der privaten Klasse SR.
Throw New ArgumentNullException("Buffer", SR.GetString("ArgumentNull_Array"))
Jede Bibliothek besitzt eine solche Klasse, die den Zugriff auf die zur Bibliothek gehörenden Text-Ressourcen ermöglicht.
Zum Zugriff auf die Texte werden drei Objekte benötigt. Zunächst ist dies das Assembly, indem die Text-Ressource enthalten ist. Dann die Bezeichnung der Ressource und den Namen des Textes. Folgender Dump zeigt den Aufbau:
Die im folgenden beschriebene Klasse ermöglicht das Auslesen der Texte.
SystemMsg stellt die Methode GetString in mehren Varianten bereit:
Variante | Beschreibung |
---|---|
GetString(ByVal Name As String) | In allen geladenen Assemblies wird nach dem angegebenen Literal gesucht. Wird es nicht gefunden, wird eine Exception geworfen. |
GetString(ByVal Name As String, DefaultValue As String) | In allen geladenen Assemblies wird nach dem angegebenen Literal gesucht. Wird es nicht gefunden, wird der angegebene Standard-Text zurückgeliefert. |
GetString(Assembly As Assembly, ByVal Name As String) As String | Im angegebenen Assembly wird nach dem angegebenen Literal gesucht. Wird es nicht gefunden, wird eine Exception geworfen. |
GetString(Assembly As Assembly, ByVal Name As String, DefaultValue As String) | Im angegebenen Assembly wird nach dem angegebenen Literal gesucht. Wird es nicht gefunden, wird der angegebene Standard-Text zurückgeliefert. |
Die Implementierung ist zugegebenermaßen nicht besonders ressourcenschonend und performant. Da aber in der Regel nur gelegentliche Aufrufe stattfinden, sollte dies kein Problem sein.
Imports System.Resources
Imports System.Reflection
''' <summary>
''' SystemResources stellt eine Methode bereit, mit der auf die lokalisierten Fehlertexte von .NET zugegriffen werden kann.
''' </summary>
Public Class SystemMsg
''' <summary>
''' Liefert die lokalisierte Meldung mit der angegebenen Bezeichnung.
''' </summary>
''' <param name="Name">Name des Strings.</param>
''' <returns>Die lokalisierte Meldung.</returns>
''' <remarks>Es wird in allen geladenen Assemblies gesucht. Wird der Text nicht gefunden, wird eine Exception geworfen.</remarks>
''' <exception cref="ArgumentException">Das angegebene Literal wurde nicht gefunden.</exception>
Public Shared Function GetString(ByVal Name As String) As String
For Each mAssembly In AppDomain.CurrentDomain.GetAssemblies()
Try
'Einrichten eines Ressourcen-Managers
Dim mResources = New ResourceManager(mAssembly.GetName().Name, mAssembly) ' Der Ressourcen-Name ist "System"
Dim txt = mResources.GetString(Name, Nothing)
If txt <> "" Then
Return txt
End If
Catch
End Try
Next
Throw New ArgumentException(GetString("Arg_EnumLitValueNotFound", "Literal value was not found."), "Name")
End Function
''' <summary>
''' Liefert die lokalisierte Meldung mit der angegebenen Bezeichnung.
''' </summary>
''' <param name="Name">Name des Strings.</param>
''' <param name="DefaultValue">Wenn das angegeben Literal nicht gefunden wurde, wird statt dessen dieser Wert ausgeben.</param>
''' <returns>Die lokalisierte Meldung.</returns>
''' <remarks>Es wird in allen geladenen Assemblies gesucht.</remarks>
Public Shared Function GetString(ByVal Name As String, DefaultValue As String) As String
For Each mAssembly In AppDomain.CurrentDomain.GetAssemblies()
Try
'Einrichten eines Ressourcen-Managers
Dim mResources = New ResourceManager(mAssembly.GetName().Name, mAssembly) ' Der Ressourcen-Name ist "System"
Dim txt = mResources.GetString(Name, Nothing)
If txt <> "" Then
Return txt
End If
Catch
End Try
Next
Return DefaultValue
End Function
''' <summary>
''' Liefert die lokalisierte Meldung mit der angegebenen Bezeichnung.
''' </summary>
''' <param name="Assembly">Assembly, in dessen Ressourcen gesucht werden soll.</param>
''' <param name="Name">Name des Strings.</param>
''' <returns>Die lokalisierte Meldung.</returns>
''' <remarks>Es wird in allen geladenen Assemblies gesucht. Wird der Text nicht gefunden, wird eine Exception geworfen.</remarks>
''' <exception cref="ArgumentException">Das angegebene Literal wurde nicht gefunden.</exception>
Public Shared Function GetString(Assembly As Assembly, ByVal Name As String) As String
Try
'Einrichten eines Ressourcen-Managers
Dim mResources = New ResourceManager(Assembly.GetName().Name, Assembly) ' Der Ressourcen-Name ist "System"
Dim txt = mResources.GetString(Name, Nothing)
If txt <> "" Then
Return txt
End If
Catch
End Try
Throw New ArgumentException(GetString("Arg_EnumLitValueNotFound", "Literal value was not found."), "Name")
End Function
''' <summary>
''' Liefert die lokalisierte Meldung mit der angegebenen Bezeichnung.
''' </summary>
''' <param name="Assembly">Assembly, in dessen Ressourcen gesucht werden soll.</param>
''' <param name="Name">Name des Strings.</param>
''' <param name="DefaultValue">Wenn das angegeben Literal nicht gefunden wurde, wird statt dessen dieser Wert ausgeben.</param>
''' <returns>Die lokalisierte Meldung.</returns>
Public Shared Function GetString(Assembly As Assembly, ByVal Name As String, DefaultValue As String) As String
Try
'Einrichten eines Ressourcen-Managers
Dim mResources = New ResourceManager(Assembly.GetName().Name, Assembly) ' Der Ressourcen-Name ist "System"
Dim txt = mResources.GetString(Name, Nothing)
If txt <> "" Then
Return txt
End If
Catch
End Try
Return DefaultValue
End Function
End Class
Wer sich nicht darauf verlassen möchte, dass die Texte bei folgenden Version immer noch funktionieren, kann mit diesem kleinen Tool die aktuell hinterlegten Texte auslesen: