Schlagwort: Softwareentwicklung

Traceroute per C# 👍 👎

In früheren Beiträgen hatte ich bereits erläutert, wie man per C# auf eine Konsolenausgabe zugreifen und programmatisch einen Ping durchführen kann. Dieser Beitrag soll nun ein einfaches Tracerouting per C# nachbilden. Dazu implementieren wir im Folgenden eine einfache (und wie üblich auf das Wesentliche reduzierte) Klasse, welche die Funktionalität durch sukzessive Erhöhung des TTL-Wertes für schlichte Ping-Pakete umsetzt.
Klasse implementieren
01020304050607080910111213141516171819202122232425
public class Traceroute : IDisposable {    private static readonly byte[] buffer = new byte[] {        0x01, 0x03, 0x03, 0x07    };  // Daten zur Übertragung
private readonly Ping ping = new Ping();

public IEnumerable<PingReply> Send(string hostNameOrAddress, int timeout = 3000) { // Paket mit TTL=1 initialisieren PingOptions pingOptions = new PingOptions(1, false);
PingReply pingReply = null;
do { pingReply = this.ping.Send(hostNameOrAddress, timeout, Traceroute.buffer, pingOptions);
// TTL für nächsten Schritt inkrementieren pingOptions.Ttl++;
yield return pingReply; } while(pingReply.Status != IPStatus.Success); }
public void Dispose() => this.ping.Dispose();}
Die Verwendung gestaltet sich nun sehr einfach:
Klasse verwenden (exkl. Namensauflösung)
0102030405
using(Traceroute traceroute = new Traceroute()) {    foreach(PingReply pingReply in traceroute.Send("coders-online.net")) {        Console.WriteLine(pingReply.Address);    }}
Um die entsprechenden Hostnamen zu den jeweiligen IP-Adressen zu ermitteln, kann beispielsweise die Methode Dns.GetHostEntry(…) dienen:
Klasse verwenden (inkl. Namensauflösung)
0102030405060708091011
using(Traceroute traceroute = new Traceroute()) {    foreach(string hostNameOrAddress in traceroute.Send("coders-online.net").Select(pR => {        try {            return Dns.GetHostEntry(pR.Address).HostName;        } catch {            return pR.Address.ToString();        }    })) {        Console.WriteLine(hostNameOrAddress);    }}

Objekte mit C# dynamisch erzeugen 👍 👎

Insbesondere bei der Entwicklung von unterstützenden Tools kann es hilfreich sein, Objekte dynamisch erzeugen zu können, ohne vorher den konkreten Typ zu kennen. Ich habe so etwas beispielsweise einmal im Rahmen einer interaktiven API-Dokumentation genutzt. Das .NET-Framework bietet hierfür die Activator-Klasse.

Als Basis für das Beispiel soll folgende triviale Klasse dienen:
Beispielklasse
01020304050607080910111213141516
public class Person {    public string FirstName {        get; set;    }
public string LastName { get; set; }
public Person() {}
public Person(string firstName, string lastName) { this.FirstName = firstName; this.LastName = lastName; }}
Hiervon können wir nun dynamisch ein Objekt erzeugen:
Objekt dynamisch erzeugen
01020304
Activator.CreateInstance(Type.GetType("Person"), new[] {    "Holger",    "Stehle"});
Dieses Vorgehen ist jedoch nur in Ausnahmefällen zu empfehlen, da ihr schließlich die Vorteile der statischen Typisierung größtenteils verliert. Es bietet sich daher je nach Anwendungsfall die Verwendung von Schnittstellen (z. B. bei Plugins) oder die Verwendung generischer Programmierung (z. B. zur internen Abstraktion) an.

Die in diesem Beitrag vorgestellte Klasse bietet auch eine Variante mit Typparameter an:
Objekt per Typparameter erzeugen
01
Person person = Activator.CreateInstance<Person>();
Diese Funktionalität ist in der Praxis zur "normalen" Entwicklung jedoch nur bedingt hilfreich, schließlich musste dazu der Typ bereits vorab bekannt sein und ihr hättet das Objekt auch einfach per new erzeugen können.

Mit generischer Programmierung zeigt sich ein weiteres Einsatzfeld, welches sich jedoch mit einer entsprechenden Einschränkung des Typparameters auch anderweitig lösen lässt und für mehr Unterstützung des Typsystems sorgt, da ihr für eure Zwecke weitere Einschränkungen (wie beispielsweise Schnittstellen) angeben könnt:
Objekt per Typparameter-Einschränkung erzeugen
01020304050607
public static class ObjectUtility {    public static T CreateInstance<T>() where T : new() {        return new T();    }}
Person person = ObjectUtility.CreateInstance<Person>();

Vorlage für React-Testseite 👍 👎

React schnell und einfach ohne größeren Einrichtungsaufwand ausprobieren: (Skripte evtl. lokal speichern)
Testvorlage
010203040506070809101112131415161718192021222324
<!DOCTYPE html><html>    <head>        <script src="https://unpkg.com/babel-standalone/babel.min.js"></script>        <script src="https://unpkg.com/react/umd/react.production.min.js"></script>        <script src="https://unpkg.com/react-dom/umd/react-dom.production.min.js"></script>
<script type="text/babel"> class MyApp extends React.Component { render() { return <strong>Hallo, Welt!</strong>; } }
ReactDOM.render( <MyApp />, document.getElementById('app') ); </script> </head> <body> <div id="app"></div> </body></html>
Bitte beachtet jedoch, dass diese (minimalistische) Vorlage nicht für den produktiven Einsatz geeignet ist.

C#-Member als obsolet kennzeichnen 👍 👎

Hin und wieder kann es sinnvoll sein, Programmelemente (z. B. Eigenschaften oder Methoden) als obsolet zu kennzeichnen. Dies ist insbesondere bei der Umsetzung allgemeiner Programmbibliotheken hilfreich, beispielsweise um den Anwender auf eine entfallende bzw. verbesserte Funktionalität hinzuweisen.

.NET stellt hierfür das Obsolete-Attribut zur Dekoration entsprechender Teile bereit. Die Verwendung ist intuitiv:
Programmelemente als obsolet kennzeichnen
01020304050607080910111213
[Obsolete("Bitte verwenden Sie .NET-Standardfunktionalität.")]public static class Sorting {    [Obsolete("Bitte verwenden Sie zumindest " + nameof(Mergesort) + ".", true)]    public static string[] Bogosort(string[] data) {        /* ohne Implementierung */        return data;    }
public static string[] Mergesort(string[] data) { /* ohne Implementierung */ return data; }}
Bei Verwendung dieser Klasse erscheint nun folgende Warnung in Visual Studio:
"Sorting" ist veraltet: "Bitte verwenden Sie .NET-Standardfunktionalität."
Bei Verwendung der Methode Bogosort erscheint zusätzlich folgender Fehler:
"Sorting.Bogosort(string[])" ist veraltet: "Bitte verwenden Sie zumindest Mergesort."

Parameter einer C#-Methode per Reflexion ermitteln 👍 👎

In einem früheren Beitrag hatte ich beschrieben, wie sich die Parameter einer Methode in Java programmatisch ermitteln lassen. Zur Reflexion in C# möchte ich gerne einen etwas ausführlicheren Beitrag schreiben; auf Grund mehrfacher Nachfrage möchte ich zwischenzeitlich jedoch zumindest eine ähnliche Funktionalität für C# vorstellen:
Parameter einer C#-Methode per Reflexion ermitteln
0102030405060708
public static IEnumerable<Dictionary<string, string>> GetMethodParameterList(    string typeName,    string methodName) {    return Type.GetType(typeName).GetMethods()        .Where(m => m.Name == methodName)        .Select(m => m.GetParameters().ToDictionary(k => k.Name, v => v.ParameterType.Name));}
Die Verwendung gestaltet sich sehr einfach; wir ermitteln dazu z. B. alle Parameter für Console.WriteLine:
Methode verwenden und Ergebnis auf der Standardausgabe ausgeben
010203040506070809101112
IEnumerable<Dictionary<string, string>> methodParameterList = GetMethodParameterList(    "System.Console",    "WriteLine");
foreach(Dictionary<string, string> method in methodParameterList) { foreach(KeyValuePair<string, string> parameter in method) { Console.WriteLine($"{parameter.Value} {parameter.Key}"); }
Console.WriteLine();}
Falls sich jemand über die verschachtelte Struktur wundert sei darauf hingewiesen, dass es auf Grund der Technik des Überladens mehrere Methoden gleicher Bezeichnung und daher auch mehrere Parameter-Listen geben kann.

Projektverweise

Kategorien / Archiv  |  Übersicht RSS-Feed

Schlagworte

Suche