Generische Typen

  • Moin moin cpg,


    die generischen Typen machen mir echt das Leben schwer. Ich hab eine Funktion mit "t" als Rückgabetyp, dieser wird als generischer Typ mitgegeben:


    [cs]public t read<t>()[/cs]


    Innerhalb der Funktion schaue ich, was t eigentlich für n Typ hat. Je nach dem les ich per BinaryReader halt den angeforderten Datentyp aus:


    [cs]switch (typeof(t).Name.ToUpper()){case ("STRING"):{return m_brPacketReader.ReadString();} case ("BYTE"): {return m_brPacketReader.ReadByte();}
    ...
    [/cs]


    Jetzt meckert da aber der compiler weil ich string/byte/... nicht nach t casten kann :(
    Bisher hab ichs so gehalten, dass der Rückgabetyp object ist, aber die Lösung finde ich nicht so prickelnd, erfordert bei jedem Aufruf n cast...


    [cs] _nmSock._clientName = (string)name_answer.read<string>();
    [/cs]

    Mein Affenkasten :)


    Intel Core i7 920 @ 3,4 GHz
    11GB Corsair XMS3 DDR3 RAM
    MSI X58 Platinum
    Sapphire HD4870 512MB (GPU @ 820MHz | MEM @ 1050MHz)
    2TB HDD
    60 GB OCZ Agility 3 SSD
    Windows 8 Professional - Dank sei der MSDNAA :)

  • Das Problem ist, dass das Framework an der Stelle nicht weiß ob du den Rückgabe wert nach T casten darfst oder nicht und deswegen ist es erst einmal verboten.
    Du kannst den Type aber "manuell" ändern über Convert.ChangeType.


    So sollte es gehen:



    Edit: Oder du castest es zuerst auf Object und dann wieder auf T


    [cs]using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;


    namespace TryOutProject
    {
    class genericSampleClass
    {


    public string readString(){
    return "";
    }


    public int readInt(){
    return 0;
    }


    public bool readBoolean(){
    return true;
    }


    public byte readByte()
    {
    return 0;
    }


    public T read<T>()
    {
    switch(typeof(T).FullName.ToUpper())
    {
    case ("BYTE"):
    {
    return (T)(object)readByte();
    }


    case ("INT"):
    {
    return (T)(object)readInt();
    }


    case ("BOOL"):
    {
    return (T)(object)readBoolean();
    }


    case ("STRING"):
    {
    return (T)(object)readString();
    }


    default:
    {
    return default(T);
    }
    }
    }
    }
    }[/cs]

  • frage, was ist mit dem "as" caster?
    der schmeißt ja keinen fehler wenn ers nicht kann, gibt hald "null" zurück. da wir aber "wissen" dass es stimmt, wird das eh nicht passieren.


    seh ich das falsch? (neu im C# /.NEt gebiet)
    edit:
    ich meine

    Code
    1. case ("BYTE"):
    2. {
    3. return readByte() as T;
    4. }
  • Würde auch gehen, dann muss man aber eine Klassenbeschränkung für T angeben


    [cs]using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;


    namespace TryOutProject
    {
    class genericSampleClass
    {


    public string readString(){
    return "";
    }


    public int readInt(){
    return 0;
    }


    public bool readBoolean(){
    return true;
    }


    public byte readByte()
    {
    return 0;
    }


    public T read<T>() where T : class
    {
    switch(typeof(T).FullName.ToUpper())
    {
    case ("BYTE"):
    {
    return (readByte() as T);
    }


    case ("INT"):
    {
    return (readInt() as T);
    }


    case ("BOOL"):
    {
    return (readBoolean() as T);
    }


    case ("STRING"):
    {
    return (readString() as T);
    }


    default:
    {
    return default(T);
    }
    }
    }
    }
    }
    [/cs]

  • ok.. das geht nicht.. int, byte und deren freunde sind ja keine Nullable types, daher ist der "as" operator unzulässig.
    ich geh mal davon aus dass durch das "where T : class" schon read<int>() einen compile-fehler verursacht

  • Funktioniert wunderbar, man dankt ;)

    Mein Affenkasten :)


    Intel Core i7 920 @ 3,4 GHz
    11GB Corsair XMS3 DDR3 RAM
    MSI X58 Platinum
    Sapphire HD4870 512MB (GPU @ 820MHz | MEM @ 1050MHz)
    2TB HDD
    60 GB OCZ Agility 3 SSD
    Windows 8 Professional - Dank sei der MSDNAA :)

  • andere frage: warum convertiert ihr da dreimal hin und her und schreib einen fixen string ins case?
    für mich sieht das ja nicht so schön aus.

    Code
    1. switch(typeof(T).FullName.ToUpper())
    2. {
    3. case ("BYTE"):
    4. {
    5. return (readByte() as T);
    6. }


    wieso nicht so?

    Code
    1. switch(typeof(T))
    2. {
    3. case (typeof(byte)):
    4. {
    5. return (readByte() as T);
    6. }


    da typeof ein operator ist, schätze ich, dass typeof(byte) schon zur compilezeit ausgewertet wird und somit diese lösung nicht nur "schöner" sondern auch performanter wäre

  • Hier, das spart dir ein paar Zeilen code. :)
    [cs]public T Read<T>()
    {
    byte[] tmp;
    int size = Marshal.SizeOf(typeof(T));
    tmp = reader.ReadBytes(size);
    IntPtr ptr = Marshal.AllocHGlobal(size);
    Marshal.Copy(tmp, 0, ptr, size);
    T value = (T)Marshal.PtrToStructure(ptr, typeof(T));
    Marshal.FreeHGlobal(ptr);
    return value;
    }[/cs]

    Zitat

    Dr. Gregory House: You've gotta get down here. They've got a satellite aimed directly into Cuddy's vagina. I told them that chances of invasion are slim to none but...

  • andere frage: warum convertiert ihr da dreimal hin und her und schreib einen fixen string ins case?
    für mich sieht das ja nicht so schön aus.

    Code
    1. switch(typeof(T).FullName.ToUpper())
    2. {
    3. case ("BYTE"):
    4. {
    5. return (readByte() as T);
    6. }


    wieso nicht so?

    Code
    1. switch(typeof(T))
    2. {
    3. case (typeof(byte)):
    4. {
    5. return (readByte() as T);
    6. }


    da typeof ein operator ist, schätze ich, dass typeof(byte) schon zur compilezeit ausgewertet wird und somit diese lösung nicht nur "schöner" sondern auch performanter wäre


    Weil Type nicht nullable ist und somit vom switch nicht akzeptiert wird.
    Es ist nicht schön, ja. Ich hätte auch einfach ein Dictonary<Type, Action> genommen.

  • ok, das hab ich wieder nicht ausprobiert ;)
    ... c#/.net ist so cool, dass man auch strings für switches (kannst in c++ und java vergessen) verwenden kann, aber System.Type nicht?... is ja doof