Interpolierte Zeichenfolgen mit C#
Im früheren Beitrag String.Format per Objekt-Eigenschaften hatte ich eine kleine Erweiterungsmethode vorgestellt, um eine etwas besser lesbare Variante der
String.Format
-Methodengruppe vorzustellen. Selbstverständlich wird C# aber beständig weiterentwickelt und so gibt es seit C# 6.0 (.NET 4.6) eine entsprechende Möglichkeit, ohne jedoch – wie in meinem kleinen Beispiel – auf die umfangreichen Formatierungsoptionen verzichten zu müssen:
Beispiele für interpolierte Zeichenfolgen
Die wesentliche Syntax-Erweiterung ist dementsprechend "010203040506070809101112131415
// Einfache Verwendung und Methodenaufrufconst string firstName = "Holger";const string lastName = "Stehle";
string formatted = $"{lastName.ToUpper()}, {firstName}"; // "STEHLE, Holger"
// Basis für Zahlenconst int num1 = 42;
formatted = $"dec: {num1}, hex: {num1:X3}"; // "dec: 42, hex: 02A"
// Dezimalstellen für Zahlenconst double num2 = 13.37;
formatted = $"{num2:N3} / {num2:N4}"; // "13,370 / 13,3700" [DE]
$
" zur Einleitung derartiger Zeichenketten. 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
Die Verwendung gestaltet sich nun sehr intuitiv:
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. 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 );}
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
Die Verwendung gestaltet sich nun sehr einfach:
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();}
Klasse verwenden (exkl. Namensauflösung)
Um die entsprechenden Hostnamen zu den jeweiligen IP-Adressen zu ermitteln, kann beispielsweise die Methode 0102030405
using(Traceroute traceroute = new Traceroute()) { foreach(PingReply pingReply in traceroute.Send("coders-online.net")) { Console.WriteLine(pingReply.Address); }}
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
Als Basis für das Beispiel soll folgende triviale Klasse dienen:
Die in diesem Beitrag vorgestellte Klasse bietet auch eine Variante mit Typparameter an: 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
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:
Activator
-Klasse.Als Basis für das Beispiel soll folgende triviale Klasse dienen:
Beispielklasse
Hiervon können wir nun dynamisch ein Objekt erzeugen:
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; }}
Objekt dynamisch erzeugen
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.01020304
Activator.CreateInstance(Type.GetType("Person"), new[] { "Holger", "Stehle"});
Die in diesem Beitrag vorgestellte Klasse bietet auch eine Variante mit Typparameter an: 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:
Vorlage für React-Testseite
React schnell und einfach ohne größeren Einrichtungsaufwand ausprobieren: (Skripte evtl. lokal speichern)
Testvorlage
Bitte beachtet jedoch, dass diese (minimalistische) Vorlage nicht für den produktiven Einsatz geeignet ist. 010203040506070809101112131415161718192021
<!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>
Project links
-
BitStadt – Stadtportal
Berlin · Hamburg · Amsterdam -
CCC – Fahrplan
Schedules for the CCCongress
Categories / Archive | Übersicht
- PHP functions in C# (136)
- Dictionary (257)
Tags
.NET · ADO.NET · Work · ASP.NET MVC · Blog · C# · Generics · Society · Computer Science · Java · LINQ · Logic · Mathematics · Network · PHP · Project · Security · Software development · Studies · Technics · Theory · Web design · WPF