Schlagwort: Softwareentwicklung

Dateityp mit C# ermitteln 👍 👎

Das ermitteln eines Dateityps nur durch Prüfen von Rohdaten kann aufwendig und fehlerträchtig sein; praktischerweise steht jedoch die native Funktion FindMimeFromData zur Verfügung, welche wir nutzen werden:
Wrapper für native Funktionalität bereitstellen
01020304050607080910111213141516171819202122232425
public static class DataUtility {    public static string GetMimeType(byte[] data) {        DataUtility.FindMimeFromData(0, null, data, (uint) data.Length, null, 0, out uint address, 0);
// Daten kopieren und Speicher freigeben IntPtr ptr = new IntPtr(address); string mimeType = Marshal.PtrToStringAuto(ptr); Marshal.FreeCoTaskMem(ptr);
return mimeType; }

[DllImport("urlmon")] private static extern uint FindMimeFromData( uint pBC, string pwzUrl, byte[] pBuffer, uint cbSize, string pwzMimeProposed, uint dwMimeFlags, out uint ppwzMimeOut, uint dwReserverd );}
Die Verwendung gestaltet sich nun sehr intuitiv:
Wrapper für native Funktionalität verwenden
0102
string mimeType = DataUtility.GetMimeType(File.ReadAllBytes("Avatar.gif")); // "image/gif"mimeType = DataUtility.GetMimeType(File.ReadAllBytes("Impressum.htm"));     // "text/html"
Beachtet jedoch bitte, dass auch diese Funktion u. U. nur begrenzt aussagekräftige Ergebnisse liefern kann und wie üblich verzichtet die Implementierung auf umfangreiche Fehlerbehandlung. Darüber hinaus bietet die native Funktion weitere Möglichkeiten, so beispielsweise das Übergeben eines Dateinamens bzw. einer URL.

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."

Projektverweise

Kategorien / Archiv  |  Übersicht RSS-Feed

Schlagworte

Suche