fix code blocks

This commit is contained in:
2026-09-10 22:54:41 +02:00
parent 2dc30200a1
commit cd8a75ec13
9 changed files with 519 additions and 666 deletions
+143 -153
View File
@@ -19,55 +19,53 @@ Für dieses Beispiel habe ich eine kleine Konsolen-Anwendung geschrieben (TestAp
**TestClass.cs**
```
using System.Security.Cryptography;
using System.Text;
namespace TestProject {
class TestClass {
public string Name { get ; set ; }
public string Surname { get ; set ; }
private string Password { get ; set ; }
public string GetFullName() {
return string .Format( "{0} {1}" , Name ?? string .Empty, Surname ?? string .Empty).Trim();
```csharp
using System.Security.Cryptography;
using System.Text;
namespace TestProject {
class TestClass {
public string Name { get ; set ; }
public string Surname { get ; set ; }
private string Password { get ; set ; }
public string GetFullName() {
return string .Format( "{0} {1}" , Name ?? string .Empty, Surname ?? string .Empty).Trim();
}
public void SetPasswort( string password){
public void SetPasswort( string password){
Password = password;
}
private static string CalcPassword( string password){
MD5 md5 = MD5 .Create();
private static string CalcPassword( string password){
MD5 md5 = MD5 .Create();
byte [] data = md5.ComputeHash( Encoding .Default.GetBytes(password));
StringBuilder hashPassword = new StringBuilder ();
foreach ( byte b in data){
StringBuilder hashPassword = new StringBuilder ();
foreach ( byte b in data){
hashPassword.Append(b);
}
return hashPassword.ToString();
return hashPassword.ToString();
}
public static string DoSomething( string value) {
public static string DoSomething( string value) {
// do something
return value;
return value;
}
}
```
**SecondTestClass.cs**
```
namespace TestProject {
public class SecondTestClass {
public int Addition( int a, int b) {
return a + b;
```csharp
namespace TestProject {
public class SecondTestClass {
public int Addition( int a, int b) {
return a + b;
}
public int Multiply( int a, int b) {
return a * b;
public int Multiply( int a, int b) {
return a * b;
}
public double Divide( int a, int b) {
if (b == 0) return 0;
return a / b;
public double Divide( int a, int b) {
if (b == 0) return 0;
return a / b;
}
}
}
.
.
```
## Auslesen von Assembly- Type-Informationen
@@ -76,33 +74,32 @@ Mit der Methode Thread.GetDomain().GetAssemblies() bekommt man alle referenziert
Um sich nun alle Assemblies der aktuellen Domäne anzeigen zu lassen, könnte man folgendes schreiben:
```
static void Main( string [] args) {
SecondTestClass secondTestClass = new SecondTest Class ();
Assembly [] assemblies = Thread .GetDomain().GetAssemblies();
foreach ( var assembly in assemblies) {
```csharp
static void Main( string [] args) {
SecondTestClass secondTestClass = new SecondTest Class ();
Assembly [] assemblies = Thread .GetDomain().GetAssemblies();
foreach ( var assembly in assemblies) {
Console .WriteLine( string .Format( "-- {0} ver.: {1}" , assembly.GetName().Name
, assembly.GetName().Version));
, assembly.GetName().Version));
}
Console .ReadLine();
}
```
.
Nun könnte man noch alle zur Verfügung stehenden Typen(Klassen) aus der TestProject-Assembly anzeigen.
```
static void Main( string [] args) {
SecondTestClass secondTestClass = new SecondTestClass ();
Assembly [] assemblies = Thread .GetDomain().GetAssemblies();
foreach ( var assembly in assemblies) {
```csharp
static void Main( string [] args) {
SecondTestClass secondTestClass = new SecondTestClass ();
Assembly [] assemblies = Thread .GetDomain().GetAssemblies();
foreach ( var assembly in assemblies) {
Console .WriteLine( string .Format( "-- {0} ver.: {1}" , assembly.GetName().Name
, assembly.GetName().Version));
if (assembly.GetName().Name.Equals( "TestProject" )) {
, assembly.GetName().Version));
if (assembly.GetName().Name.Equals( "TestProject" )) {
Type [] types = assembly.GetTypes();
foreach ( var type in types) {
Console .WriteLine( " ++{0}" , type.Name);
foreach ( var type in types) {
Console .WriteLine( " ++{0}" , type.Name);
}
}
}
@@ -110,24 +107,23 @@ Console .ReadLine();
}
```
.
Wenn man nun allerdings Informationen eines bestimmten Types haben möchte, so werden diese Informationen aus den Metadaten des Moduls geladen, in dem sich der Type befindet. Um zum Beispiel alle öffentlichen Methoden eines Types anzuzeigen, könnte man folgendes schreiben:
```
static void Main( string [] args) {
SecondTestClass secondTestClass = new SecondTestClass ();
Assembly [] assemblies = Thread .GetDomain().GetAssemblies();
foreach ( var assembly in assemblies) {
```csharp
static void Main( string [] args) {
SecondTestClass secondTestClass = new SecondTestClass ();
Assembly [] assemblies = Thread .GetDomain().GetAssemblies();
foreach ( var assembly in assemblies) {
Console .WriteLine( string .Format( "-- {0} ver.: {1}" , assembly.GetName().Name
, assembly.GetName().Version));
if (assembly.GetName().Name.Equals( "TestProject" )) {
, assembly.GetName().Version));
if (assembly.GetName().Name.Equals( "TestProject" )) {
Type [] types = assembly.GetTypes();
foreach ( var type in types) {
Console .WriteLine( " ++ {0}" , type.Name);
foreach ( var type in types) {
Console .WriteLine( " ++ {0}" , type.Name);
MethodInfo [] methodInfos = type.GetMethods();
foreach ( var info in methodInfos) {
Console .WriteLine( " ++ {0}" , info.Name);
foreach ( var info in methodInfos) {
Console .WriteLine( " ++ {0}" , info.Name);
}
}
}
@@ -136,11 +132,10 @@ Console .ReadLine();
}
```
.
Es fällt auf, dass auch die Methoden ToString, Equals, GetHashCode und GetType in beiden Klassen angezeigt werden, obwohl diese in den Klassen überhaupt nicht deklariert wurden. Das liegt daran, dass alle Typen von object ableiten und object diese Methoden implementiert. Was noch auffällt ist, dass nur öffentliche Methoden angezeigt werden. Möchte man sich auch die privaten Methoden anzeigen lassen, so muss man der Methode type.GetMethods Parameter übergeben. Diese Methode verlangt BindingFlags, die man mit dem Bitweise ODER-Operator (|) miteinander verknüpfen kann. Um sich nun öffentliche und private Methoden anzeigen zu lassen, muss der Aufruf der Methode type.GetMethods folgendermaßen lauten:
```
```csharp
MethodInfo[] methodInfos = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
```
@@ -148,81 +143,80 @@ Dieser Aufruf gibt an, dass man alle öffentlichen und nicht-öffentlichen Insta
Das ganze könnte man natürlich noch in der Form weiter treiben, dass man sich die kompletten Methodensignaturen mit Modifizierer, Schlüsselwort und Rückgabewert anzeigen lässt:
```
static void Main( string [] args) {
SecondTestClass secondTestClass = new SecondTestClass ();
Assembly [] assemblies = Thread .GetDomain().GetAssemblies();
foreach ( var assembly in assemblies) {
```csharp
static void Main( string [] args) {
SecondTestClass secondTestClass = new SecondTestClass ();
Assembly [] assemblies = Thread .GetDomain().GetAssemblies();
foreach ( var assembly in assemblies) {
Console .WriteLine( string .Format( "-- {0} ver.: {1}" , assembly.GetName().Name, assembly.GetName().Version));
if (assembly.GetName().Name.Equals( "TestProject" )) {
if (assembly.GetName().Name.Equals( "TestProject" )) {
Type [] types = assembly.GetTypes();
foreach ( var type in types) {
Console .WriteLine( " ++ {0}" , type.Name);
MethodInfo [] methodInfos = type.GetMethods( BindingFlags .Public | BindingFlags .NonPublic
| BindingFlags .Instance
| BindingFlags .Static);
foreach ( var info in methodInfos) {
string modifier = GetModifier(info);
string keyword = GetKeyword(info);
string parameters = GetParameters(info);
if (! string .IsNullOrEmpty(keyword)) {
keyword = string .Format( "{0} " , keyword);
foreach ( var type in types) {
Console .WriteLine( " ++ {0}" , type.Name);
MethodInfo [] methodInfos = type.GetMethods( BindingFlags .Public | BindingFlags .NonPublic
| BindingFlags .Instance
| BindingFlags .Static);
foreach ( var info in methodInfos) {
string modifier = GetModifier(info);
string keyword = GetKeyword(info);
string parameters = GetParameters(info);
if (! string .IsNullOrEmpty(keyword)) {
keyword = string .Format( "{0} " , keyword);
}
Console .WriteLine( " ++ {0} {1}{2}{3}({4})" , modifier, keyword
, info.ReturnParameter, info.Name, parameters);
Console .WriteLine( " ++ {0} {1}{2}{3}({4})" , modifier, keyword
, info.ReturnParameter, info.Name, parameters);
}
}
}
}
Console .ReadLine();
}
private static string GetModifier( MethodInfo info) {
if (info.IsPublic) return "public" ;
return "private" ;
private static string GetModifier( MethodInfo info) {
if (info.IsPublic) return "public" ;
return "private" ;
}
private static string GetKeyword( MethodInfo info) {
if (info.IsStatic) return "static" ;
if (info.IsVirtual) return "virtual" ;
return string .Empty;
private static string GetKeyword( MethodInfo info) {
if (info.IsStatic) return "static" ;
if (info.IsVirtual) return "virtual" ;
return string .Empty;
}
private static string GetParameters( MethodInfo info) {
StringBuilder parameters = new StringBuilder ();
private static string GetParameters( MethodInfo info) {
StringBuilder parameters = new StringBuilder ();
ParameterInfo [] parameterInfos = info.GetParameters();
if (parameterInfos != null ) {
foreach ( ParameterInfo parameterInfo in parameterInfos) {
if (! string .IsNullOrEmpty(parameters.ToString())) {
if (parameterInfos != null ) {
foreach ( ParameterInfo parameterInfo in parameterInfos) {
if (! string .IsNullOrEmpty(parameters.ToString())) {
parameters.Append( ", " );
}
parameters.AppendFormat( "{0} {1}" , parameterInfo.ParameterType.Name, parameterInfo.Name);
}
}
return parameters.ToString();
return parameters.ToString();
}
```
.
Nicht immer ist bereits während der Entwicklung bekannt, aus welchem Assembly man Informationen benötigt. Sodass die Methode Thread.GetDomain().GetAssemblies() nicht verwendet werden kann. Eine weitere Möglichkeit an ein Assembly zu kommen ist es direkt zu laden. Dafür bietet die Klasse Assembly die statische Methode Assembly.LoadFrom zum Laden von Assemblies. Statt dem Laden des Assembly über die aktuelle Domäne, wird das nächste Beispiel so modifiziert, dass die TestProject-Assembly direkt aus einem Verzeichnis heraus geladen wird.
```
static void Main( string [] args) {
Assembly assembly = Assembly .LoadFrom( @"c:\TestProject.dll" );
if (assembly != null ) {
```csharp
static void Main( string [] args) {
Assembly assembly = Assembly .LoadFrom( @"c:\TestProject.dll" );
if (assembly != null ) {
Console .WriteLine( string .Format( "-- {0} ver.: {1}" , assembly.GetName().Name, assembly.GetName().Version));
Type [] types = assembly.GetTypes();
foreach ( var type in types) {
Console .WriteLine( " ++ {0}" , type.Name);
foreach ( var type in types) {
Console .WriteLine( " ++ {0}" , type.Name);
MethodInfo [] methodInfos =
type.GetMethods( BindingFlags .Public | BindingFlags .NonPublic | BindingFlags .Instance |
type.GetMethods( BindingFlags .Public | BindingFlags .NonPublic | BindingFlags .Instance |
BindingFlags .Static);
foreach ( var info in methodInfos) {
string modifier = GetModifier(info);
string keyword = GetKeyword(info);
string parameters = GetParameters(info);
if (! string .IsNullOrEmpty(keyword)) {
keyword = string .Format( "{0} " , keyword);
foreach ( var info in methodInfos) {
string modifier = GetModifier(info);
string keyword = GetKeyword(info);
string parameters = GetParameters(info);
if (! string .IsNullOrEmpty(keyword)) {
keyword = string .Format( "{0} " , keyword);
}
Console .WriteLine( " ++ {0} {1}{2}{3}({4})" , modifier, keyword, info.ReturnParameter,
Console .WriteLine( " ++ {0} {1}{2}{3}({4})" , modifier, keyword, info.ReturnParameter,
info.Name, parameters);
}
}
@@ -237,21 +231,21 @@ Man sieht, dass die gleiche Ausgabe wie bereits im vorherigen Beispiel generiert
Nachdem die Vorgehensweise nun klar sein sollte, möchte ich nun den eigentlich interessanten Teil demonstrieren. Wie kann man nun auf Methoden usw. zugreifen und wie können Werte aus einem Type gelesen und veränder werden? Wenn man die Methode SecondTestClass.Addition(int a, int b) aufrufen möchte, dann braucht man die Methodeninformationen von dem Type SecondTestClass aus dem TestProject-Assembly. D.h. man muss wie in den obigen Beispielen auch über alle Typen iterieren, um an den gesuchten Type SecondTestClass zu kommen. Hat man den gesuchten Type gefunden, so kann man sich von diesem alle Methoden in einem Array zurückgeben lassen. Dieses Array kann dann wieder ganz normal durchlaufen und nach der gewünschten Methode durchsucht werden. Hat man die Methode gefunden so muss zuerst eine Instanz von dem Objekt erzeugt werden und dafür gibt es den Activator, der die statische Methode CreateInstance beinhaltet. Als Parameter übergibt man ihr den Type von dem eine Instanz erzeugt werden soll. Jetzt kann man über die MethodInfo die Methode aufrufen. Dazu muss der Methode die Instanz des Objektes übergeben werden, von welchem die Methode aufgerufen werden soll und zusätzlich noch ein Array von Objekten, welche die zu übergebenen Parameter beinhaltet. Hat die Methode keine Parameter, so muss null übergeben werden. Dabei muss der Rückgabewert in den erwarteten Wert gecastet werden. Das ganze könnte dann folgendermaßen aussehen:
```
static void Main( string [] args) {
Assembly assembly = Assembly .LoadFrom( @"c:\TestProject.dll" );
if (assembly != null ) {
```csharp
static void Main( string [] args) {
Assembly assembly = Assembly .LoadFrom( @"c:\TestProject.dll" );
if (assembly != null ) {
Console .WriteLine( string .Format( "-- {0} ver.: {1}" , assembly.GetName().Name, assembly.GetName().Version));
Type [] types = assembly.GetTypes();
foreach ( var type in types) {
if (type.Name.Equals( "SecondTestClass" )) {
Console .WriteLine( " ++ {0}" , type.Name);
foreach ( var type in types) {
if (type.Name.Equals( "SecondTestClass" )) {
Console .WriteLine( " ++ {0}" , type.Name);
MethodInfo [] methodInfos = type.GetMethods();
foreach ( var info in methodInfos) {
if (info.Name.Equals( "Addition" )) {
object obj = Activator .CreateInstance(type);
int value = ( int )info.Invoke(obj, new object [] { 2, 5 });
Console .WriteLine( " ++ {0}(2 + 5) = {1}" , info.Name, value);
foreach ( var info in methodInfos) {
if (info.Name.Equals( "Addition" )) {
object obj = Activator .CreateInstance(type);
int value = ( int )info.Invoke(obj, new object [] { 2, 5 });
Console .WriteLine( " ++ {0}(2 + 5) = {1}" , info.Name, value);
}
}
}
@@ -263,18 +257,17 @@ Console .ReadLine();
Aufruf der Methode Addition
.
Bei statischen Methoden kann das Erzeugen der Instanz weggelassen werden und für den Parameter des Instanz-Objektes kann null übergeben werden.
```
if (type.Name.Equals( "TestClass" )) {
Console .WriteLine( " ++ {0}" , type.Name);
MethodInfo [] methodInfos = type.GetMethods( BindingFlags .NonPublic | BindingFlags .Static);
foreach ( var info in methodInfos) {
if (info.Name.Equals( "CalcPassword" )) {
string value = ( string )info.Invoke( null , new object [] { "myPassword" });
Console .WriteLine( " ++ {0}(\"myPassword\") = {1}" , info.Name, value);
```csharp
if (type.Name.Equals( "TestClass" )) {
Console .WriteLine( " ++ {0}" , type.Name);
MethodInfo [] methodInfos = type.GetMethods( BindingFlags .NonPublic | BindingFlags .Static);
foreach ( var info in methodInfos) {
if (info.Name.Equals( "CalcPassword" )) {
string value = ( string )info.Invoke( null , new object [] { "myPassword" });
Console .WriteLine( " ++ {0}(\"myPassword\") = {1}" , info.Name, value);
}
}
}
@@ -282,24 +275,23 @@ Console .WriteLine( " ++ {0}(\"myPassword\") = {1}" , info.Name, value);
Das übergebene Passwort wurde über eine statische Methode gehashed.
.
Um den Wert einer Property auszulesen, muss anstelle von MethodInfo die PropertyInfo verwendet werden. Aus dieser kann dann über die Methode PropertyInfo.GetValue der aktuelle Wert zurückgegeben werden. Da in diesem Beispiel nach dem Instanzieren des Objektes noch keine Werte zugewiesen wurden, sind die Properties leer.
```
static void Main( string [] args) {
Assembly assembly = Assembly .LoadFrom( @"C:\ TestProject.dll" );
if (assembly != null ) {
```csharp
static void Main( string [] args) {
Assembly assembly = Assembly .LoadFrom( @"C:\ TestProject.dll" );
if (assembly != null ) {
Console .WriteLine( string .Format( "-- {0} ver.: {1}" , assembly.GetName().Name, assembly.GetName().Version));
Type [] types = assembly.GetTypes();
foreach ( var type in types) {
if (type.Name.Equals( "TestClass" )) {
Console .WriteLine( " ++ {0}" , type.Name);
object obj = Activator .CreateInstance(type);
PropertyInfo [] propertyInfos = type.GetProperties( BindingFlags .Public | BindingFlags .NonPublic
| BindingFlags .Instance);
foreach ( var info in propertyInfos) {
Console .WriteLine( " ++ {0} = {1}" , info.Name, info.GetValue(obj, null ));
foreach ( var type in types) {
if (type.Name.Equals( "TestClass" )) {
Console .WriteLine( " ++ {0}" , type.Name);
object obj = Activator .CreateInstance(type);
PropertyInfo [] propertyInfos = type.GetProperties( BindingFlags .Public | BindingFlags .NonPublic
| BindingFlags .Instance);
foreach ( var info in propertyInfos) {
Console .WriteLine( " ++ {0} = {1}" , info.Name, info.GetValue(obj, null ));
}
}
}
@@ -308,25 +300,23 @@ Console .ReadLine();
}
```
.
Wenn man nun die Properties mit Werten belegen möchte, so muss man analog zur Methode PropertyInfo.GetValue, die Methode PropertyInfo. SetValue verwenden.
```
if (type.Name.Equals( "TestClass" )) {
Console .WriteLine( " ++ {0}" , type.Name);
PropertyInfo [] propertyInfos = type.GetProperties( BindingFlags .Public | BindingFlags .NonPublic
| BindingFlags .Instance);
propertyInfos[0].SetValue(obj, "Peter" , null );
propertyInfos[1].SetValue(obj, "Müller" , null );
propertyInfos[2].SetValue(obj, "myPassword" , null );
foreach ( var info in propertyInfos) {
Console .WriteLine( " ++ {0} = {1}" , info.Name, info.GetValue(obj, null ));
```csharp
if (type.Name.Equals( "TestClass" )) {
Console .WriteLine( " ++ {0}" , type.Name);
PropertyInfo [] propertyInfos = type.GetProperties( BindingFlags .Public | BindingFlags .NonPublic
| BindingFlags .Instance);
propertyInfos[0].SetValue(obj, "Peter" , null );
propertyInfos[1].SetValue(obj, "Müller" , null );
propertyInfos[2].SetValue(obj, "myPassword" , null );
foreach ( var info in propertyInfos) {
Console .WriteLine( " ++ {0} = {1}" , info.Name, info.GetValue(obj, null ));
}
}
```
.
## Wozu braucht man jetzt aber nun die Reflection?