Die Version 4.5 der .NET-Framework-Klassenbibliothek (.NET Framework Class Library – FCL) enthält 947 neue Klassen. Davon entfallen jeweils mehr als 10 oder mehr neue Klassen auf die 13 in der folgenden Tabelle genannten FCL-Namensräume.
Namensraum
|
Anzahl
neuer Klassen
|
Bemerkung
|
System.IdentityModel
|
216
|
Windows
Identity Foundation (WIF
|
System.Web
|
150
|
Neue
Klassen für ASP.NET Webforms und ASP.NET MVC
|
System.Windows
|
143
|
Neue
Klassen für WPF, insbesondere das Ribbon-Steuerelement
|
System.Activities
|
81
|
Neue
Klassen für Workflow
|
System.Net
|
76
|
Neue
Klassen für HTTP-Netzwerkprogrammierung sowie Websockets
|
System.ServiceModel
|
74
|
Neue
Klassen für WCF
|
System.ComponentModel
|
38
|
Neue
Klassen für Datenannotationen
|
System.Runtime
|
36
|
Neue
Klassen für Interoperabilität mit WinRT, und Ladeprofiloptimierung
|
Microsoft.Build
|
28
|
Neue
Klassen für msbuild.exe
|
System.Data
|
26
|
Neue
Klassen für ADO.NET Entity Framework
|
System.Diagnostics
|
24
|
Neue
Klassen für Event Tracing for Windows (ETW)
|
System.Security
|
15
|
Klassen
für Windows Identity Foundation (WIF)
|
System.Reflection
|
10
|
u.a.
neue Klassen für Assemby-Metadaten
|
Insgesamt steigert sich damit die Anzahl der beim .NET mitgelieferten Klassen auf 13.524.
Klassenstatistik .NET 1.0 bis 4.5
In den kommenden Wochen werde ich in einer Artikelserie zehn Neuerungen in der .NET-Klassenbibliothek vorstellen, die nicht die großen Bibliotheken WCF, WPF, Entity Framework, WF, WIF, ASP.NET und TPL betreffen und daher nicht so im Licht der Öffentlichkeit stehen.
Neuigkeiten in der .NET-Klassenbibliothek, Teil 1: Aufruferinformationen (Caller Info)
Gelegentlich besteht der Bedarf, dass eine Methode ihren Aufrufer kennt, z. B. für Ablaufverfolgung und Diagnosezwecke. Seit .NET 1.0 gibt es die Möglichkeit, den sogenannten Stacktrace abzurufen:
System.Diagnostics.StackTrace t = new System.Diagnostics.StackTrace();
foreach (var f in t.GetFrames())
{
Console.WriteLine(f);
}
Dabei ist es jedoch immer etwas mühsam, den direkten Aufrufer herauszufiltern. Neu in der .NET-Klasssenbibliothek ist nun, dass durch .NET-Attribut eine Methode diese Aufruferinformationen direkt vom Compiler als Parameter erhält (vgl. __FILE__ und __LINE__ in C++). Die folgende Abbildung zeigt, wie man diese speziellen Parameter definiert. Sie erscheinen als optionale Parameter für den Aufrufer. Dieser muss sie jedoch zwingend leer lassen, damit der Compiler sie befüllen kann. Besser wäre es gewesen, wenn Visual Studio diese Parameter ganz ausblenden würde.
Aufruferinformationen durch Caller-Info-Attribute
Ausgabe des obigen Beispiels
Da die Injizierung der Werte durch den Compiler erfolgt und nicht wie beim Stacktrace zur Laufzeit ermittelt wird, sieht man bei den Caller-Info-Attributen auch nach einer Obfuskation noch die ursprünglichen Methodennamen. Das bedeutet aber dann auch: Caller-Info-Attribute schwächen die Obfuskation, denn im Deompiler sieht man dennoch den Namen der aufrufenden Methoden:
int fhiuahfdheiadfgzaegfegfkhgetfwdhjadslf =
this.adfgzaegfegfkhgetfwdhjad (10, "Run",
"h:\\TFS\\Demo\\NET45\\NET45Demos\\Konsole45CS
\\FCL\\CallerInformer.cs", 21);
Es gibt keinen Unterschied zwischen Debug- und Release-Kompilierung.
Sinnvoll sind die Caller-Info-Attribute für die Realisierung des INotifyPropertyChanged-Mechanismus. Bisher musste jede Property im Setter einen eigenen Namen an das Ereignis übergeben. Nun kann man das in einer Datenklasse eleganter lösen, in dem eine Hilfsroutine in der Klasse das CallerMemberName-Attribut verwendet, siehe das Beispiel:
public void Run3()
{
var d = new Datenobjekt();
d.PropertyChanged += delegate { Console.WriteLine
("Wert geändert!"); };
d.Wert = 10;
}
...
class Datenobjekt : System.ComponentModel.INotifyPropertyChanged
{
public event System.ComponentModel.PropertyChangedEventHandler
PropertyChanged;
/// <summary>
/// Realisierung in .NET 4.5, ohne dass der Aufrufer den
/// Property-Namen übergeben muss
/// </summary>
/// <param name="propertyName"></param>
private void NotifyPropertyChanged([CallerMemberName]
String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new
System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
private int wert;
public int Wert
{
get { return wert; }
set { wert = value; NotifyPropertyChanged(); }
}
}
()