Das My-Feature in Visual Basic 2005 erlaubt einen einfachen Zugriff auf gängige Funktionalitäten des .NET Frameworks. Mitunter einfacher als das in C# möglich ist. Letztendlich handelt es sich dabei aber nur um die Kapselung der Funktionen unterschiedlicher Klassen in einer gemeinsamen Klasse - und was liegt da näher, als die enthaltene Funktionalität nachzubilden?
Den Anfang macht die AssemblyInfo-Klasse (My.Application.Info). Sie liefert die Informationen, die in der Konfigurationsdatei Ihrer Applikation enthalten sind. Unter anderem also den Firmennamen, Copyright-Informationen oder den Produktnamen. Die Klasse ist verhältnismäßig leicht zu implementieren; der Name soll auch unter C# AssemblyInfo sein. Die Implementierung beginnt mit den Feldern, die die Daten aufnehmen sollen.
private Assembly _assembly = null; private string _companyName = null; private string _copyright = null; private string _description = null; private string _productName = null; private string _title = null; private string _trademark = null; |
Die Daten sind in der Datei AssemblyInfo.cs zu finden und dort in Form von Attributen angegeben. Diese Attribute müssenausgewertet werden, und dafür bietet sich sinnvollerweise Reflection an. Die Methode GetAttribute<T>() liefert die Werte des angegebenen Attributs.
private T GetAttribute<T>() where T : Attribute {
T[] result = (T[])this._assembly.GetCustomAttributes( typeof(T), true ); if ( result.Length == 0 ) { return null; } return result[0]; }
|
Unschwer zu erkennen ist, dass es sich bei dieser Methode um eine generische Methode handelt. Die Einschränkung auf Attribute (und damit auf Referenztypen) ermöglicht es, innerhalb der Methode den Wert null zurückliefern zu können. Das würde nicht ohne die Einschränkung funktionieren (dann wäre es möglich, dass T ein Wertetyp ist, somit wäre null als Wert nicht mehr zulässig).
Der nächste Schritt ist nun die Implementierung der Eigenschaften. Die meisten erhalten ihre Informationen über die Methode GetAttribute<T>(). Hier einige beispielhafte Implementierungen:
public string CompanyName { get { if ( String.IsNullOrEmpty( this._companyName ) ) { AssemblyCompanyAttribute attribute = GetAttribute<AssemblyCompanyAttribute>(); if ( attribute == null ) this._companyName = String.Empty; else this._companyName = attribute.Company; }
return this._companyName; } }
public string Copyright { get { if ( String.IsNullOrEmpty( this._copyright ) ) { AssemblyCopyrightAttribute attribute = GetAttribute<AssemblyCopyrightAttribute>(); if ( attribute == null ) this._copyright = String.Empty; else this._copyright = attribute.Copyright; } return this._copyright; } }
public string Description { get { if ( String.IsNullOrEmpty( this._description ) ) { AssemblyDescriptionAttribute attribute = GetAttribute<AssemblyDescriptionAttribute>(); if ( attribute == null ) this._description = String.Empty; else this._description = attribute.Description; } return this._description; } }
|
Fast alle dieser Eigenschaften funktionieren dann analog, wobei natürlich darauf geachtet werden muss, dass das korrekte Attribut übergeben wird. Andere wiederum erfordern nur einen Zugriff auf eine andere Klasse, wie z.B. WorkingSet (das aus Environment ermittelt werden kann) oder AssemblyName (das aus dem Namen der Assembly ermittelt werden kann).
public string AssemblyFullName { get { return this._assembly.FullName; } }
public string AssemblyName { get { return this._assembly.GetName().Name; } }
public System.Version Version { get { return this._assembly.GetName().Version; } }
public long WorkingSet { get { return Environment.WorkingSet; } }
public string DirectoryPath { get { return Path.GetDirectoryName( this._assembly.Location ); } }
|
Etwas komplizierter ist die Implementierung der Eigenschaft LoadedAssemblies. Diese liefert eine generische Read-Only-Liste zurück, die alle referenzierten Assemblies enthält. Die Klasse ReadOnlyCollection<T>() finden Sie im Namespace System.Collections.Objectmodel.
public ReadOnlyCollection<Assembly> LoadedAssemblies { get { List<Assembly> result = new List<Assembly>();
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
for ( int i = 0; i < assemblies.Length; i++ ) result.Add( assemblies[i] );
return new ReadOnlyCollection<Assembly>( result ); } }
|
Bleibt als Letztes nur noch die Implementierung des Konstruktors:
public AssemblyInfo( Assembly currentAssembly ) {
if ( currentAssembly == null ) throw new NullReferenceException( "Es muss eine Assembly übergeben werden" ); else this._assembly = currentAssembly; }
|
Damit wäre die Implementierung komplett. Nun können Sie auf einfache Weise auf die Eigenschaften Ihrer Applikation zugreifen. Allerdings nur lesend - um die Daten in der AssemblyInfo.cs zu ändern müssen sie nach wie vor selbst eingreifen. Hier nochmals der Code komplett.
using System; using System.Collections.Generic; using System.Collections.ObjectModel ; using System.Text; using System.Reflection; using System.IO;
namespace Csharp.My {
class AssemblyInfo {
private Assembly _assembly = null; private string _companyName = null; private string _copyright = null; private string _description = null; private string _productName = null; private string _title = null; private string _trademark = null;
public string AssemblyFullName { get { return this._assembly.FullName; } }
public string AssemblyName { get { return this._assembly.GetName().Name; } }
public string CompanyName { get { if ( String.IsNullOrEmpty( this._companyName ) ) { AssemblyCompanyAttribute attribute = GetAttribute<AssemblyCompanyAttribute>(); if ( attribute == null ) this._companyName = String.Empty; else this._companyName = attribute.Company; }
return this._companyName; } }
public string Copyright { get { if ( String.IsNullOrEmpty( this._copyright ) ) { AssemblyCopyrightAttribute attribute = GetAttribute<AssemblyCopyrightAttribute>(); if ( attribute == null ) this._copyright = String.Empty; else this._copyright = attribute.Copyright; } return this._copyright; } }
public string Description { get { if ( String.IsNullOrEmpty( this._description ) ) { AssemblyDescriptionAttribute attribute = GetAttribute<AssemblyDescriptionAttribute>(); if ( attribute == null ) this._description = String.Empty; else this._description = attribute.Description; } return this._description; } }
public string ProductName { get { if ( String.IsNullOrEmpty( this._productName ) ) { AssemblyProductAttribute attribute = GetAttribute<AssemblyProductAttribute>(); if ( attribute == null ) this._productName = String.Empty; else this._productName = attribute.Product; } return this._productName; } }
public string Title { get { if ( String.IsNullOrEmpty( this._title ) ) { AssemblyTitleAttribute attribute = GetAttribute<AssemblyTitleAttribute>(); if ( attribute == null ) this._title = String.Empty; else this._title = attribute.Title; } return this._title; } }
public string Trademark { get { if ( String.IsNullOrEmpty( this._title ) ) { AssemblyTrademarkAttribute attribute = GetAttribute<AssemblyTrademarkAttribute>(); if ( attribute == null ) this._trademark = String.Empty; else this._trademark = attribute.Trademark; } return this._trademark; } }
public System.Version Version { get { return this._assembly.GetName().Version; } }
public long WorkingSet { get { return Environment.WorkingSet; } }
public string DirectoryPath { get { return Path.GetDirectoryName( this._assembly.Location ); } }
public string StackTrace { get { return Environment.StackTrace; } }
public ReadOnlyCollection<Assembly> LoadedAssemblies { get { List<Assembly> result = new List<Assembly>();
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
for ( int i = 0; i < assemblies.Length; i++ ) result.Add( assemblies[i] );
return new ReadOnlyCollection<Assembly>( result ); } }
private T GetAttribute<T>() where T : Attribute {
T[] result = (T[])this._assembly.GetCustomAttributes( typeof( T ), true ); if ( result.Length == 0 ) { return null; } return result[0]; }
public AssemblyInfo( Assembly currentAssembly ) {
if ( currentAssembly == null ) throw new NullReferenceException( "Es muss eine Assembly übergeben werden" ); else this._assembly = currentAssembly; }
} }
|