C# Reflectie onder de knie: runtime-typeontdekking en dynamische programmering
Reflectie-objecten worden gebruikt om type-informatie tijdens runtime op te halen. De klassen die toegang bieden tot de metadata van een draaiend programma, bevinden zich in de System.Reflection-naamruimte.
De System.Reflection-naamruimte bevat klassen waarmee u informatie over de applicatie kunt verkrijgen en dynamisch typen, waarden en objecten aan de applicatie kunt toevoegen.
Toepassingen van Reflectie
Reflectie heeft de volgende toepassingen:
Het maakt het mogelijk attribuutinformatie tijdens runtime te bekijken.
Het stelt het bestuderen van verschillende typen in een assembly en het instantiëren ervan toe.
Het maakt late binding aan methoden en eigenschappen mogelijk.
Het maakt het aanmaken van nieuwe typen tijdens runtime en het uitvoeren van taken met die typen mogelijk.
Metadata bekijken
In het voorgaande hoofdstuk hebben we aangegeven dat u met reflectie attribuutinformatie kunt bekijken.
Het MemberInfo-object van de System.Reflection-klasse moet geïnitialiseerd worden om de attributen te ontdekken die aan een klasse zijn gekoppeld. Hiervoor definieert u een object van de doelklasse als volgt:
System.Reflection.MemberInfo info = typeof(MyClass);
Het volgende programma demonstreert dit:
using System;
[AttributeUsage(AttributeTargets.All)]
public class HelpAttribute : System.Attribute {
public readonly string Url;
public string Topic { // Topic is een benoemde parameter
get { return topic; }
set { topic = value; }
}
public HelpAttribute(string url) { // url is een positionele parameter
this.Url = url;
}
private string topic;
}
[HelpAttribute("Informatie over de klasse MyClass")]
class MyClass { }
namespace AttributeAppl {
class Program {
static void Main(string[] args) {
System.Reflection.MemberInfo info = typeof(MyClass);
object[] attributes = info.GetCustomAttributes(true);
for (int i = 0; i < attributes.Length; i++) {
System.Console.WriteLine(attributes[i]);
}
Console.ReadKey();
}
}
}
Wanneer het gecompileerd en uitgevoerd wordt, toont het de naam van de aangepaste attributen die aan de klasse MyClass zijn gekoppeld:
HelpAttribute
Voorbeeld
In dit voorbeeld gebruiken we het DeBugInfo-attribuut dat in het vorige hoofdstuk is gemaakt en gebruiken reflectie om metadata in de Rectangle-klasse uit te lezen.
Live Demousing System;
using System.Reflection;
namespace BugFixApplication {
// een aangepast attribuut BugFix dat aan een klasse en zijn leden toegewezen kan worden
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = true)]
public class DeBugInfo : System.Attribute {
private int bugNo;
private string developer;
private string lastReview;
public string message;
public DeBugInfo(int bg, string dev, string d) {
this.bugNo = bg;
this.developer = dev;
this.lastReview = d;
}
public int BugNo { get { return bugNo; } }
public string Developer { get { return developer; } }
public string LastReview { get { return lastReview; } }
public string Message {
get { return message; }
set { message = value; }
}
}
[DeBugInfo(45, "Zara Ali", "12/8/2012", Message = "Return type mismatch")]
[DeBugInfo(49, "Nuha Ali", "10/10/2012", Message = "Unused variable")]
class Rectangle {
// lidvariabelen
protected double length;
protected double width;
public Rectangle(double l, double w) {
length = l;
width = w;
}
[DeBugInfo(55, "Zara Ali", "19/10/2012", Message = "Return type mismatch")]
public double GetArea() {
return length * width;
}
[DeBugInfo(56, "Zara Ali", "19/10/2012")]
public void Display() {
Console.WriteLine("Length: {0}", length);
Console.WriteLine("Width: {0}", width);
Console.WriteLine("Area: {0}", GetArea());
}
} // einde klasse Rectangle
class ExecuteRectangle {
static void Main(string[] args) {
Rectangle r = new Rectangle(4.5, 7.5);
r.Display();
Type type = typeof(Rectangle);
// itereren door de attributen van de Rectangle-klasse
foreach (Object attributes in type.GetCustomAttributes(false)) {
DeBugInfo dbi = (DeBugInfo)attributes;
if (null != dbi) {
Console.WriteLine("Bug nr: {0}", dbi.BugNo);
Console.WriteLine("Ontwikkelaar: {0}", dbi.Developer);
Console.WriteLine("Laatst bekeken: {0}", dbi.LastReview);
Console.WriteLine("Opmerkingen: {0}", dbi.Message);
}
}
// itereren door de methode-attributen
foreach (MethodInfo m in type.GetMethods()) {
foreach (Attribute a in m.GetCustomAttributes(true)) {
DeBugInfo dbi = (DeBugInfo)a;
if (null != dbi) {
Console.WriteLine("Bug nr: {0}, voor Methode: {1}", dbi.BugNo, m.Name);
Console.WriteLine("Ontwikkelaar: {0}", dbi.Developer);
Console.WriteLine("Laatst bekeken: {0}", dbi.LastReview);
Console.WriteLine("Opmerkingen: {0}", dbi.Message);
}
}
}
Console.ReadLine();
}
}
}
Wanneer de bovenstaande code wordt gecompileerd en uitgevoerd, produceert het het volgende resultaat:
Length: 4.5 Width: 7.5 Area: 33.75 Bug nr: 49 Ontwikkelaar: Nuha Ali Laatst bekeken: 10/10/2012 Opmerkingen: Unused variable Bug nr: 45 Ontwikkelaar: Zara Ali Laatst bekeken: 12/8/2012 Opmerkingen: Return type mismatch Bug nr: 55, voor Methode: GetArea Ontwikkelaar: Zara Ali Laatst bekeken: 19/10/2012 Opmerkingen: Return type mismatch Bug nr: 56, voor Methode: Display Ontwikkelaar: Zara Ali Laatst bekeken: 19/10/2012 Opmerkingen:
C Taal
- C# Hello World – Uw eerste C# applicatie bouwen
- C# Keywords en Identifiers begrijpen: Regels, lijsten en best practices
- C# Variabelen & Primitive Datatypes onder de knie krijgen: Complete gids
- C# Operators – Uitgebreide gids voor operators in C#
- C# Bitwise en Bit Shift Operators: Een Uitgebreide Gids
- C# Fundamentals: Invoer en Uitvoer Basis
- C# Expressies, Statements & Blokken: Uitgebreide Gids met Praktische Voorbeelden
- C# Comments Onder de Loep: Types, Best Practices en XML Documentatie
- C# Break Statement: Hoe en Wanneer Te Gebruiken
- C# Continue Statement: Effectief Lusiteraties Overslaan
- C# Arrays: Declaratie, Initialisatie en Operaties