Deklaration eines generischen Interfaces mit integralen Datentypen

  • C#
  • .NET (FX) 4.5–4.8

Es gibt 6 Antworten in diesem Thema. Der letzte Beitrag () ist von loeffel.

    Deklaration eines generischen Interfaces mit integralen Datentypen

    Moin Leute.
    Ich steuere diverse Hardwaren über zugeschnittene Klassen an, die gemeinsame Interfaces implementieren.
    Da entweder die eine oder die andere Hardware zum Einsatz kommt, sind diese Projekte nicht im Hauptprogramm verlinkt, sondern werden über CreateInstance() der vorgefundenen Interdace-DLLs instanziiert, dabei sind beim Kunden nur diejenigen DLLs vorhanden, für die auch die entsprechende Hardware geliefert wurde.
    Nun haben wir Messkarten, wo die (sehr langen) Daten-Listen mal als List<sbyte> und mal als List<int> zurückgeben werden.
    Dafür möchte ich einen eleganten Konstrukt formulieren:

    Quellcode

    1. public interface IDetector<T> where T: sbyte, int, IDisposable
    2. {
    3. // hier käme dann int oder sbyte zurück
    4. void GetType(T type);
    5. // ...
    6. }
    nur dass der C#-Compiler dies nicht erlaubt.
    Kennt jemand von Euch eine elegante Lösung für dieses Problem?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Hallo,
    mit welcher C#-Version arbeitest du? Mit .NET7 könntest du folgendes machen

    C#-Quellcode

    1. ​using System.Numerics;
    2. interface IDetector<T, U>
    3. where U : INumber<U>
    4. where T : List<U>
    5. {
    6. void GetType(T value);
    7. }
    8. class C : IDetector<List<int>, int>
    9. {
    10. public void GetType(List<int> value)
    11. {
    12. throw new NotImplementedException();
    13. }
    14. }


    So ist zumindest sichergestellt, das Typ U auf jeden Fall ein Zahl-Typ ist.
    Und sbyte ist nicht CLS Compliant. Verwende besser short.
    @RodFromGermany
    Ich verstehe das Problem nicht so richtig, kannst du das nochmal genauer beschreiben? GetType ist doch void, was kommt da zurück?

    @ISliceUrPanties
    Ähhh, nicht jedes Programm soll immer eine DLL sein, die man veröffentlicht und über mehrere .NET Sprachen verfügbar machen muss. Ich verzichte doch nicht in allen C# Projekten auf uint und ulong, nur weil das im Interface bei VB Probleme macht falls das mal jemand verweisen sollte. Aber gut, kann ja jeder machen wie er möchte.
    Danke für Eure Ausführungen.
    @ISliceUrPanties Framework 4.8.
    Das sbyte kommt nicht von mir, sondern vom Hersteller der Hardware.
    @Bluespide GetType() wäre meine eigene Prozedur.

    Ich werde ein Enum mit einer Aufzählung der möglichen Datentypen machen und dann die Werte in dieser Art zurückgeben:

    C#-Quellcode

    1. public enum ValueTypeKind
    2. {
    3. SByte,
    4. Int,
    5. }
    6. public interface IDetector: IDisposable
    7. {
    8. ValueTypeKind GetValues(object data);
    9. }
    Die Daten werden dann anhand des Enums entsprechend gecastet und weiter verarbeitet.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Hey Ron,
    [
    Wenn du in der Lage bist, das NuGet Package System.Memory zu verwenden (war fuer .NET Framework, nicht? Fuer .NET [Core] brauchst du das nicht), kannst du das mit Span<T> oder Memory<T> loesen. Dabei gibt es die Moeglichkeit, deine Datenquelle in die "Bitness" zu casten, die du brauchst:

    C#-Quellcode

    1. using System;
    2. using System.Runtime.InteropServices;
    3. class Program
    4. {
    5. static void Main()
    6. {
    7. // Beispiel 1: Quelle ist Byte-Array
    8. byte[] byteArray = new byte[64];
    9. new Random().NextBytes(byteArray); // Zufallsdaten.
    10. Span<byte> byteSpanFromByteArray = new Span<byte>(byteArray);
    11. ProcessBytes(byteSpanFromByteArray);
    12. // Beispiel 2: Quelle ist Int-Array - stell sicher, dass die Buffergroessen passen!!!
    13. int[] intArray = new int[16]; // 16 * 4 bytes = 64 bytes
    14. new Random().Next(intArray); // Wieder Zufallsdaten.
    15. Span<byte> byteSpanFromIntArray = MemoryMarshal.Cast<int, byte>(new Span<int>(intArray));
    16. ProcessBytes(byteSpanFromIntArray);
    17. }
    18. static void ProcessBytes(Span<byte> byteSpan)
    19. {
    20. // Process the Span<byte>
    21. foreach (byte value in byteSpan)
    22. {
    23. Console.Write(value + " ");
    24. }
    25. Console.WriteLine();
    26. }
    27. }


    Probier mal aus, ob das funktioniert (zusammenkopiert, manuell editiert, nie getestet... :) )

    Die Performance-Unterschiede in .NET Framework und .NET koennen in diesen Bereichen uebrigens wirklich erheblich sein.
    Migration zu .NET kann also durchaus mehr als Sinn machen.
    @loeffel Ron ist der bei Harry Potter. ;)
    Ja, das ist Framework, ich habe den Titel angepasst.
    Es brauchte außerdem das NuGet Package System.Runtime.CompilerServices.Unsafe, dann hat es geflutscht.
    Das Datenhandling kommt bei mir in derzeit 4 DLLs vor: 2 Hardware-Quellen mit unterschiedlichen Datentypen, eine Interface-DLL und das Ansteuer- und Auswerteprogramm.
    Da ich den Cast im Hauptprogramm wieder umkehren müsste, um die korrekten Daten zu lesen, werde ich bei meiner Enum-Object-Variante bleiben.
    Trotzdem: Besten Dank für Deine Bemühungen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!