NTH-Library

    • Release
    • Open Source

    Es gibt 43 Antworten in diesem Thema. Der letzte Beitrag () ist von nikeee13.

      NTH-Library

      Basierend auf der Idee von @picoflop mit seiner NTHLibrary, hier eine, die ich derzeit entwickle.

      NTH-Library
      Ziel dieser Library ist es, kleine, aber oft notwendige Funktionen, die nicht im .NET Framework enthalten sind, nachzurüsten. Dabei handelt es sich nicht nur um Extension Methods, sondern auch im ganze Klassen. Welche da u. A. zusammen kommen, kannst du bei den Samples sehen. Das NTH steht für Nice-To-Have. ;)

      Diese NTH-Library ist vorerst unabhängig vom UI (WinForms, WPF), um so wenig Abhängigkeiten wie möglich zu haben. Ich spiele aber mit dem Gedanken, jeweils eine für WinForms und WPF zu machen. Bei letzterem weiß ich aber noch überhaupt nicht, was da rein kommen könnte.

      Zusatzklassen wie z. B. die MathEx sollen die Framework-Klassen nicht ersetzen, sondern ergänzen.

      Samples

      Levenshtein-Distanz

      C#-Quellcode

      1. string a = "tier";
      2. string b = "tor";
      3. var dist = a.LevenshteinDistanceTo(b);
      4. Console.WriteLine(dist); // 2
      5. // Sortierung:
      6. var dictionary = new[] {
      7. "bier",
      8. "bitte",
      9. "bitter",
      10. "besen"
      11. };
      12. var input = "biete";
      13. var bestMatch = dictionary.OrderByLevenshteinDistanceTo(input).FirstOrDefault();
      14. Console.WriteLine("Did you mean " + bestMatch + "?"); // Did you mean bitte?

      MathEx

      C#-Quellcode

      1. MathEx.Max(1, 2, 3); // bei 3 parametern wird eine optimierte überladung verwendet
      2. // anstatt
      3. Math.Max(Math.Max(1, 2), 3);
      4. MathEx.Max(1, 2, 3, 4, 5); // mit rest-parametern

      C#-Quellcode

      1. // Math.Pow() ist leider nur für floats
      2. int @base = 2;
      3. int exponent = 4;
      4. int result = MathEx.Pow(@base, exponent); // wenn base == 2, dann wird bitshifting verwendet
      5. // Negative exponenten sind pauschal nicht möglich, da das Ergebnis nicht immer vernünftig in einen int/long passt.
      6. // ebenfalls für long verfügbar

      CommandLine-Klasse

      C#-Quellcode

      1. var newCommandLine = new CommandLine(@"C:\Demo.exe");
      2. newCommandLine.Arguments.Add("-n");
      3. newCommandLine.Arguments.Add("Some argument"); // wird automatisch in quotes gesetzt
      4. // Starte demo.exe mit folgender kommandozeile:
      5. // C:\Demo.exe -n "Some argument"
      6. ProcessEx.Start(newCommandLine);
      7. string commandLineString = newCommandLine.ToString();
      8. Console.WriteLine("Spawned process using command line:");
      9. Console.WriteLine(commandLineString);
      10. var parsedCommandLine = CommandLine.Parse(commandLineString); // Es gibt auch eine Parse-Funktion
      11. Console.WriteLine("Current arguments:");
      12. var currentExecutable = CommandLine.Current.FilePath; // CommandLine.Current gibt das Kommandozeilenobjekt zum aktuellen Prozess zurück
      13. foreach(var arg in CommandLine.Current.Arguments)
      14. Console.WriteLine(arg);

      ByteSize-Klasse

      C#-Quellcode

      1. var fileByteCount = new FileInfo(Assembly.GetEntryAssembly().Location).Length; // z. B. 5120
      2. //fileByteCount ist eine Anzahl an bytes.
      3. var fs = new ByteSize(fileByteCount);
      4. Console.WriteLine(fs.ToString()); // 5 KiB
      5. fs++; // um einen Byte inkrementieren
      6. Console.WriteLine("Exact bytes: " + fs.ByteCount);
      7. fs += new ByteSize(1, BytePrefix.MibiByte); // + 1MiB
      8. var twoGigabyte = new ByteSize(2, BytePrefix.GigaByte); // 2GB (nicht GiB)
      9. bool areEqual = fs == twoGigabyte; // sind die 2 Byte-Grössen gleich groß?

      Misc Extensions

      C#-Quellcode

      1. var pointer = new IntPtr(0xABCD);
      2. var str = pointer.ToHexString(); // "0x0000ABCD" bei 32-Bit, bei 64-Bit "0x000000000000ABCD"
      3. // der Präfix (0x) ist via Parameter ausstellbar.
      4. // Das Padding ist abhängig von der Architektur der laufenden Anwendung, kann aber via Parameter angepasst werden.
      5. // ähnliche Extension gibt es für Int32

      C#-Quellcode

      1. byte a = 0xF2;
      2. byte reversed = a.ReverseBits(); // MSB und LSB tauschen (also alle bits)

      C#-Quellcode

      1. [StructLayout(LayoutKind.Explicit)]
      2. struct SomeStruct
      3. {
      4. [FieldOffset(0)]
      5. public byte Field1;
      6. [FieldOffset(1)]
      7. public int Field2;
      8. [FieldOffset(5)]
      9. public float Field3;
      10. }
      11. // sizeof(SomeStruct) == 1 + 4 + 4 == 9 byte
      12. byte[] blobData = new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9};
      13. SomeStruct instance = blobData.ConvertToStruct<SomeStruct>();
      14. // aus dem Byte-Array wurde eine Struct-Instanz erstellt (basierend auf den Offsets usw). Nützlich beim Interop mit nativen structs/buffern
      15. byte b = instance.Field1; // == 1
      16. int c = instance.Field2; // == 0x05040302 (weil Little Endian und so)


      Die Library kann noch mehr. Einfach mal durch den Code browsen.
      U. A. nicht in den Samples gezeigt:
      - Generisches Diffing
      - BigEndianBinaryReader/-Writer
      - Crc32
      - Formatter für Byte-Sizes (basierend auf WinAPI)
      - Verschiedene Levenshtein-Implementierungen

      Weitere Samples folgen!

      Download
      NuGet: PM> Install-Package NTH

      Kompilierte Versionen auf GitHub:
      Für .NET 4.0
      4.5er-Version kommt bald, aber die 4.0er Version funktioniert dafür ja auch. Ob ich noch was für <4.0 mache, weiß ich noch nicht. Wenn Du aber das Bedürfnis danach hast, kannst du das gerne machen.

      Source Code auf GitHub:
      github.com/nikeee/nth

      Voraussetzungen:
      - .NET 4.X (Client-Profile-Version nun verfügbar)

      Work In Progress:
      - CodeContracts-Support
      - XML-Dokumentation und Online-Doku-Browser
      - Weitere Funktionen

      Projektstatus
      Dieses Projekt ist nicht fertig. Es fehlen noch einige Unittests sowie sehr viel Dokumentation. Du kannst mir dort gerne Abhilfe schaffen!

      Open Source!
      Diese Library ist Open Source (eine Lizenz muss ich noch aussuchen, vorerst gilt die GPLv3). Es wird aber gerne gesehen, wenn du selbst etwas zu dieser Library beiträgst! Einfach forken, etwas dazucoden/fixen und Pull-Request stellen.

      Wenn Ihr Inspirationen habt, immer her damit! :)
      Von meinem iPhone gesendet

      Dieser Beitrag wurde bereits 9 mal editiert, zuletzt von „nikeee13“ ()

      Das ist vielleicht falsch rübergekommen:
      Ziel bei der MathEx-Klasse (sowie dem Rest der Library) ist nicht Optimierung, sondern, dass man übersichtlicheren Code schreiben kann... oder dass man bei jeder kleinen Funktion nicht immer das Rad neu zusammenschrauben muss.
      So ist

      C#-Quellcode

      1. MathEx.Max(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
      übersichtlicher als

      C#-Quellcode

      1. Math.Max(Math.Max(Math.Max(Math.Max(1, 2), Math.Max(3, 4)), Math.Max(Math.Max(5, 6), Math.Max(7, 8))), Math.Max(9, 10))

      (z. B.)
      Von meinem iPhone gesendet
      Wenn das so ist: ein Clamp-Funktion wäre ganz hilfreich, also Min und Max in einem.
      Ungefähr so:

      C#-Quellcode

      1. int Clamp(int value, int min, int max)
      2. {
      3. if (value < min) return min;
      4. if (value > max) return max;
      5. return value;
      6. }

      Ergebnis:

      C#-Quellcode

      1. ​int value = Clamp(a, b, c);
      2. //anstatt
      3. int value = Math.Max(b, Math.Min(a, c));


      Diese Funktion brauche ich erstaunlich oft.
      Ich hatte noch ein paar Ideen:
      -Managed Versionen der wichtigsten WinAPI Methoden (2-Stufen-Wrapper: WinAPI -> Manager Klassen -> Vereinfachte Version mit Framework-Klassen), ist aber wahrscheinlich ein riesen Aufwand.
      -Erweiterungen für den System.Drawing-Namespace (unsafe-Helfer etc.)
      Was ich oft brauche ist das Auslesen bzw. Mappen von Attributen bei Enums. Ich schreibe/kopiere mir jedes mal auf's neue Funktionen dazu, es nervt.

      Beispiel:

      C#-Quellcode

      1. enum X
      2. {
      3. [DisplayName("Ganztoll")]
      4. Spitze,
      5. [DisplayName("Fantastic!")]
      6. Top
      7. }
      8. // ...
      9. var text = X.Spitze;
      10. var y = GetAttributeValue<DisplayName>(text);
      11. var x = GetEnumValue<DisplayName>(y);
      To make foobar2000 a real random music player, I figured out the only way to achieve this is to use Windows Media Player.

      At some point in time, you recognize that knowing more does not necessarily make you more happy.

      nafets3646 schrieb:

      Managed Versionen der wichtigsten WinAPI Methoden (2-Stufen-Wrapper: WinAPI -> Manager Klassen -> Vereinfachte Version mit Framework-Klassen), ist aber wahrscheinlich ein riesen Aufwand.

      Gibt es da bestimmte Funktionen an die du da denkst?
      Ich hätte noch eine Hotkey-Klasse rumliegen. Die passt nur nicht in diese Library, die würde eher in eine NTH.Windows.Forms kommen.

      nafets3646 schrieb:

      Erweiterungen für den System.Drawing-Namespace (unsafe-Helfer etc.)
      Sowas wie einen FastBitmap-Wrapper? Sowas hab ich schon, hab ich nur vergessen, hier mal reinzustellen. :P
      Gibt es momentan nur dort:
      github.com/nikeee/pixlib
      Diese Library dort reinzumergen wäre glaub ich auch zu speziell. Da ich aber auch Diffing-Kram in der NTH habe, könnte man aber trotzdem mal darüber nachdenken. Ebenso hab ich schon in Erwägung gezogen, die Subnetzberechnung aus der WakeOnLAN-Library rauszunehmen und stattdessen hier rein zu packen. Ich bin mir bei alldem aber nicht allzu sicher, also wäre es ein Leichtes, mich zu überreden. :P

      Chrisber schrieb:

      Was ich oft brauche ist das Auslesen bzw. Mappen von Attributen bei Enums.
      Kann ich machen.
      Von meinem iPhone gesendet
      Eine Funktion, die automatisch eine ArgumentNullException wirft?

      Beispiel (Extending von object):

      C#-Quellcode

      1. public void X(string y)
      2. {
      3. y.NotNull(); // prüft ob null, wenn ja, dann werfe Exception automatisch mit richtigem Namen
      4. }

      To make foobar2000 a real random music player, I figured out the only way to achieve this is to use Windows Media Player.

      At some point in time, you recognize that knowing more does not necessarily make you more happy.
      Hier mal ne kleine Liste von Dlls: dwmapi.dll, kernel32.dll, shell32.dll, user32.dll, gdi32.dll (BitBlt und die anderen, welche man sonst noch in Verbindung mit GDI+ nutzt).

      @Chrisber
      Wäre das nicht sogar über nen Tag möglich?
      @nafets3646 Soweit ich weiß, ist es nicht möglich in Attributen auf Werte der Funktionseingabe zuzugreifen. Attribute sind imho nicht Call-gebunden (keine Ahnung, wie ich das sonst beschreiben soll), sondern eher auf statische Reflection bezogen. (Achtung: Halbwissen)
      To make foobar2000 a real random music player, I figured out the only way to achieve this is to use Windows Media Player.

      At some point in time, you recognize that knowing more does not necessarily make you more happy.
      @nafets3646 Du denkst bestimmt an diese Attribute, oder? Damit würde man anscheinend nur an das X kommen, nicht aber an das y. Wenn das gehen würde, stellt sich mir auch die Frage, was passiert, wenn man "".NotNull() macht, denn ein konstanter Empty-String hat ja keinen Variablennamen.

      Generell halte ich es da für sinnvoller, CodeContracts zu benutzen. Die machen genau das und sorgen auch noch dafür, dass die IDE ne bessere semantische Analyse hat.

      Hier mal ne kleine Liste von Dlls: dwmapi.dll, kernel32.dll, shell32.dll, user32.dll, gdi32.dll
      Danke, aber dass die nicht alle in die Library passen (semantisch) ist dir klar, oder? ;)
      Es geht hier um Nice-To-Have-Funktionen, also Funktionen, die man nicht zwingend braucht, aber welche man häufig immer schnell mal selbst schreiben muss, weil sie halt fehlen. Ein kompletter WinAPI-Wrapper würde da nicht rein passen. Ich dachte da nur an einzelne Funktionen wie SendMessage, die man wirklich fast immer braucht (wobei ich SendMessage auch schon grenzwertig finde). Wenn ich Aero-Funktionen brauche, nehme ich eine UI-Library. Wenn ich einen API-Wrapper brauche, nehme ich eine Library, die dafür da ist. ;)

      Ich kämpfe aber gerade mit ganz anderen Problemen, denn ich glaube Roslyn mag mein Projekt plötzlich nicht mehr. :/
      Bilder
      • roslyn.png

        9,13 kB, 380×219, 169 mal angesehen
      Von meinem iPhone gesendet
      Hat es einen bestimmten Grund, dass du bei den Methoden Min(params int[] x) und Max(params int[] x) in der for-Schleife von hinten nach vorne gehst oder gibt es da keinen Unterschied zur entgegengesetzten Richtung, also von vorne nach hinten?
      Es hält sich immer die Legende, dass es rückwärts schneller ist, da nach jedem durchlauf mit einer Konstanten (statt arr.Length) verglichen wird.
      Das ist allerdings Mikrooptimiererei und eigentlich sinnlos. Keine Ahnung, was ich mir da gedacht habe.
      Von meinem iPhone gesendet

      nikeee13 schrieb:

      Wenn Ihr Inspirationen habt, immer her damit! :)

      Na dann! ^^
      Zu den ByteSizes: Ich habe hier auch schon mal was dazu gemacht - kannst dir ja mal anschauen. :)

      nikeee13 schrieb:

      Das ist allerdings Mikrooptimiererei und eigentlich sinnlos. Keine Ahnung, was ich mir da gedacht habe.


      Genauso wie ++i statt i++ - verwende ich auch immer noch obwohl total sinnlos. "Zu denken" gibt es da wohl nichts, ist vermutlich Gewöhnungssache.
      To make foobar2000 a real random music player, I figured out the only way to achieve this is to use Windows Media Player.

      At some point in time, you recognize that knowing more does not necessarily make you more happy.

      Gonger96 schrieb:

      Was ich nützlich fände (zumindest in jedem Projekt brauche) sind HighByte/LowByte, HighWord/LowWord etc. Als Generika ists wahrscheinlich am Schönsten. Das ist nichts Wildes, aber immer zu gebrauchen.
      Wie stellst du dir das mit Generics vor?
      Bei mir würden da nur die 4 Funktionen rauskommen:


      Higlav schrieb:

      Zu den ByteSizes: Ich habe hier auch schon mal was dazu gemacht - kannst dir ja mal anschauen.
      Das ist im Prinzip ja genau das gleiche, mit dem Unterschied, dass dort noch was für die Berechnung von Geschwindigkeiten dabei ist.
      Sowas hab ich auch schon von anfang an eingeplant, ich bin mit meiner Umsetzung aber noch nicht zufrieden. Hier mal das, was ich bisher vorhatte.:
      gist.github.com/nikeee/34dc2cfd449c399c13ad
      Von meinem iPhone gesendet
      @nikeee13
      Ich denke, das war wohl so in der Richtung gemeint:

      C#-Quellcode

      1. public static T High<T>(long value)
      2. {
      3. // Wenn T Byte ist, zweite 8 Bits der ersten 16 Bits zurückgeben
      4. // Wenn T Int16 ist, zweite 16 Bits der ersten 32 Bits zurückgeben
      5. // ... Int32
      6. }
      7. public static T Low<T>(long value)
      8. {
      9. // Wenn T Byte ist, erste 8 Bits der ersten 16 Bits zurückgeben
      10. // Wenn T Int16 ist, erste 16 Bits der ersten 32 Bits zurückgeben
      11. // ... Int32
      12. }


      Bei mir würden da nur die 4 Funktionen rauskommen:

      Und noch 2 für long -> int
      "Luckily luh... luckily it wasn't poi-"
      -- Brady in Wonderland, 23. Februar 2015, 1:56
      Desktop Pinner | ApplicationSettings | OnUtils

      Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Niko Ortner“ ()

      @Niko Ortner: Bei Generics ist es höchst sträflich, bei der Verwendung auf irgendwelche Typen zu prüfen. Alles, was man kann, ist T auf bestimtme Sachen einschränken, aber eine explizite Typenprüfung verstösst gegen das Prinzip von Generics.

      Wenn man nur bestimmte Typen zulassen will, welche man nicht mit Type Constraints limitieren kann, sollte man einfach überladen. Sonst kommt jemand noch auf die Idee und macht Low<Point>(Mouse.Position); und bekommt eine Exception, was er nicht erwartet.

      Falls man sowas macht, hat man in 90% der Fälle ein Fail im Klassendesign.

      Edit:
      Ich hab übrigens Extension Methods für den RSACryptoServiceProvider:
      github.com/nikeee/nth/blob/c66…viceProviderExtensions.cs
      Entnommen habe ich sie hier und anschließend habe ich es meinen Coding-Standards angepasst.
      Habe mit dem Autor des originalen Codes Rücksprache gehalten.

      Bis ich das in den master merge, werde ich noch nen paar Unittests machen müssen. Ich habe momentan nur 2, was für einen Crypto-Bestandteil IMO recht wenig ist. Will jemand? :D
      Von meinem iPhone gesendet

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „nikeee13“ ()