Kategorie: Softwareentwicklung

Ping per C# 👍 👎

Zwar könnte man hier ähnlich wie im Artikel Konsolenausgabe in C# verwenden für traceroute beschrieben vorgehen, jedoch bietet es sich an, die Ping-Klasse des .NET-Frameworks zu verwenden. Diese möchte ich mit diesem Beitrag kurz vorstellen, da sie interessanterweise zu den doch eher unbekannteren Funktionalitäten gehört.
Ping-Klasse verwenden
010203040506
using(Ping ping = new Ping()) {    PingReply reply = ping.Send("coders-online.net");
long time = reply.RoundtripTime; // 19 IPStatus status = reply.Status; // Success}
Es können durch entsprechende Überladungen weiterführende Optionen wie die zu übertragenden Daten festgelegt werden. Durch die seit .NET 4.5 verfügbare Methode SendPingAsync besteht außerdem auch die Möglichkeit, nach dem komfortablen und nicht-blockierenden async/await-Muster vorzugehen.

Grad-Angaben für trigonometrische Funktionen in C# 👍 👎

In einem Gespräch wurde mir kürzlich vom "seltsamen" Verhalten trigonometrischer Methoden wie Math.Sin oder Math.Cos berichtet. Nun lag das Problem jedoch weniger an C# (ohnehin kaum vorstellbar Smiley: winking), sondern vielmehr an den übergebenen Werten – diese lagen nämlich in Grad vor, wobei C# das Bogenmaß erwartet.

Glücklicherweise lassen sich die Werte jedoch schnell und problemlos jeweils zueinander umrechnen:
Umrechung von Grad <-> Bogenmaß
010203040506070809
  // Grad zu Bogenmaß umrechnenpublic static double DegToRad(double degrees) {    return (degrees * (Math.PI / 180));}
// Bogenmaß zu Grad umrechnenpublic static double RadToDeg(double radians) { return (radians * (180 / Math.PI));}
Entsprechende Funktionen habe ich im Rahmen von "PHP-Funktionen in C#" schon einmal zur Verfügung gestellt:

Langzahlarithmetik in C# 👍 👎

Für manche Anwendungen kann es notwendig werden, mit ganzen Zahlen zu arbeiten, die mitunter deutlich größer (bzw. kleiner) sind, als die CLS-Typen Int16 (short), Int32 (int) und Int64 (long) definieren.

Zwar ist es eine gute Übung, arithmetische Operationen auf ganzen Zahlen, die als Zeichenkette vorliegen, selbst zu implementieren – das .NET-Framework bringt jedoch bereits seit v4.0 die Struktur BigInteger aus System.Numerics mit. Sofern du dir also nicht sehr sicher bist, eine für deinen spezifischen Anwendungsfall bessere Implementierung vorliegen zu haben, solltest du eher auf das Framework setzen.

Die Verwendung gestaltet sich denkbar einfach, insofern belasse ich es für den Moment bei ein paar Beispielen:
BigInteger verwenden
0102030405060708091011
BigInteger a = BigInteger.Parse("34872923458349238592320478");BigInteger b = BigInteger.Parse("14782398471853465710237672");
// Operatorüberladung für BigInteger.Add(a, b)BigInteger sum = (a + b); // 49655321930202704302558150
// Operatorüberladung für BigInteger.Subtract(a, b)BigInteger difference = (a – b); // 20090524986495772882082806
// Operatorüberladung für BigInteger.Multiply(a, b)BigInteger product = (a * b); // 515505450439764661138576432136536115538523372647216
Selbstverständlich stehen noch einige andere nützliche Operationen und Indikatoren zur Verfügung.

Notwendig sind derartige Vorgehensweisen beispielsweise in der Kryptologie oder bei Simulationen in der numerischen Mathematik. Hauptsächlich kam ich jedoch deswegen auf diesen kurzen Beitrag, da einige Entwickler die Einführung dieser Struktur (BigInteger ist nicht als Klasse implementiert) verpasst zu haben scheinen. Smiley: smiling

String.Format per Objekt-Eigenschaften 👍 👎

Jeder C#-Entwickler wird sicherlich bereits die eine oder andere Überladung der String.Format-Methode verwendet haben – ansonsten wird es auf jeden Fall höchste Zeit, sich damit zu beschäftigen. Beispiel:
String.Format verwenden
0102030405
string message = String.Format("{0} ist {1} Jahre alt und besitzt {2:C}.",    "Bernd",    35,    1234.56);  // "Bernd ist 35 Jahre alt und besitzt 1234,56 €."
Noch etwas bequemer – insbesondere auch im Zusammenhang mit anonymen Typen – wäre es jedoch, die Eigenschaften eines Objekts als Ersetzungsdaten verwenden zu können. Wir werden uns dazu eine (nicht ernsthaft optimierte) Erweiterungsmethode für den Typ String schreiben, welche auf Reflexion setzt:
FormatByObject implementieren
01020304050607080910111213
public static string FormatByObject(this string str, object obj) {    StringBuilder stringBuilder = new StringBuilder(str);    {        foreach(PropertyInfo propertyInfo in obj.GetType().GetProperties()) {            stringBuilder.Replace(                "{" + propertyInfo.Name + "}",                propertyInfo.GetValue(obj).ToString()            );        }    }
return stringBuilder.ToString();}
Nun können wir statt numerischer Indizes komfortablere Zeichenketten verwenden:
FormatByObject verwenden
0102030405
message = "{Name} ist {Age} Jahre alt und besitzt {Balance} €.".FormatByObject(new {    Name = "Bernd",    Age = 35,    Balance = 1234.56});  // "Bernd ist 35 Jahre alt und besitzt 1234,56 €€."
Dieses sehr einfache Vorgehen unterstützt jedoch bei Weitem nicht alle Möglichkeiten der ursprünglichen Implementierung, so ist beispielsweise kein {Balance:C} zur Währungsformatierung möglich. Dies könnte dadurch behoben werden, indem wir unsere erweiterte Formatierung auf das Basisformat zurückführen – sprich, die Zeichenketten durch einen Index ersetzen. Ich werde dies in einem separaten Beitrag noch einmal aufgreifen.

Aufrufer-Informationen für Methoden in C# 👍 👎

Manchmal kann es sinnvoll sein, sich Informationen über den Aufrufer einer Methode übermitteln zu lassen. Wir werden dies im Folgenden mit zwei praxisnahen Beispielen genauer untersuchen.

Zuerst möchten wir ein (einfaches) Logging-System implementieren:
Logging implementieren
010203040506070809
public static class Logging {    public static void Enter(string caller) {        Trace.WriteLine(caller + " betreten");    }
public static void Leave(string caller) { Trace.WriteLine(caller + " verlassen"); }}
Diese Klasse können wir nun beispielsweise wie folgt verwenden:
Logging verwenden
010203040506070809
static void Main(string[] args) {    Logging.Enter("Main");
/** * Aktionen ausführen **/
Logging.Leave("Main");}
Nun stellt uns jedoch das .NET-Framework ein spezielles Attribut CallerMemberName zur Verfügung, um diesen Prozess ein wenig zu optimieren – dazu müssen wir unsere Klasse minimal ergänzen:
Logging-Implementierung erweitern
010203040506070809
public static class Logging {    public static void Enter([CallerMemberName] string caller = "") {        Trace.WriteLine(caller + " betreten");    }
public static void Leave([CallerMemberName] string caller = "") { Trace.WriteLine(caller + " verlassen"); }}
Der Parameter caller wird nun beim Aufruf automatisch festgelegt, so dass die explizite Angabe in Main bei gleichem Ergebnis entfallen kann.

Ich möchte noch einen weiteren praktischen Anwendungsfall mit INotifyPropertyChanged demonstrieren:
INotifyPropertyChanged mit impliziten Aufruferinformationen
01020304050607080910111213141516171819202122232425262728293031323334353637
public class Person : INotifyPropertyChanged {    public event PropertyChangedEventHandler PropertyChanged;

private string name; public string Name { get { return this.name; } set { if(this.name != value) { this.name = value;
this.OnPropertyChanged(); } } }
private int age; public int Age { get { return this.age; } set { if(this.age != value) { this.age = value;
this.OnPropertyChanged(); } } }

private void OnPropertyChanged([CallerMemberName] string propertyName = "") { this?.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); }}
Dies vereinfacht die Verwendung dieser Schnittstelle, die insbesondere zur Datenbindung im Rahmen der WPF Verwendung findet – vor allem bei Refaktorierungsmaßnahmen. Das Verhalten ist wie erwartet:
Objekt verwenden
0102030405060708091011121314151617
Person ich = new Person() {    Name = "Holger",    Age = 25};
ich.PropertyChanged += (sender, e) => { Debug.WriteLine("Der Wert der Eigenschaft '{0}' hat sich geändert!", (object) e.PropertyName );};
ich.Age = 26;
/** * Das Ereignis "PropertyChanged" wird ausgelöst * und "PropertyName" implizit auf "Age" gesetzt.**/
Weitere Informationen (und hilfreiche Attribute) lassen sich im MSDN nachlesen.

Projektverweise

Kategorien / Archiv  |  Übersicht RSS-Feed

Schlagworte

Suche