2009-04-19 3 views
1

Ich bin neu bei Generika und alles, was ich in C# finden konnte, ist List [T] - sonst nichts.C#: Wie man eine generische Methode Typ (Byte/Wort/DWORD) machen?

Dies ist der C++ Code Ich habe C#

template <class type> 
type Read() 
{ 
    type t; 
    int s = sizeof(type); 
    if(index + s > size) 
     throw(std::exception("error 101")); 
    memcpy(&t, stream + index, s); 
    index += s; 
    return t; 
} 

Sein wie die

BYTE mode = Read<BYTE>(); 
DWORD mode1 = Read<DWORD>(); 
WORD mode2 = Read<WORD>(); 

Frage genannt übersetzen in: Wie mit C# Generics zu tun?

+0

"... C++ - Code muss ich in C# übersetzen ..." Warum? Sie können Ihren vorhandenen C++ - Code aus C# auf verschiedene Arten aufrufen. Da Sie Vorlagen verwenden, wird C++/CLI wahrscheinlich der einfachste Weg für diesen speziellen Fall sein. –

Antwort

4

Ihr Code scheint die ReadInt16, ReadInt32 und ReadInt64 Methoden der BinaryReader Klasse nachzuahmen.

Es ist schwierig, eine Neuschreibung ohne Wissen über Ihre globalen Variablen bereitzustellen. Unter der Annahme, dass der Stream ein Byte-Array ist, würde der folgende Code funktionieren.

public T Read<T>() where T : struct { 
    // An T[] would be a reference type, and alot easier to work with. 
    T[] t = new T[1]; 

    // Marshal.SizeOf will fail with types of unknown size. Try and see... 
    int s = Marshal.SizeOf(typeof(T)); 
    if (_index + s > _size) 
    // Should throw something more specific. 
    throw new Exception("Error 101"); 

    // Grab a handle of the array we just created, pin it to avoid the gc 
    // from moving it, then copy bytes from our stream into the address 
    // of our array. 
    GCHandle handle = GCHandle.Alloc(t, GCHandleType.Pinned); 
    Marshal.Copy(_stream, _index, handle.AddrOfPinnedObject(), s); 

    _index += s; 

    // Return the first (and only) element in the array. 
    return t[0]; 
} 
+0

Schöne Lösung (+1). Ich würde eine 'where T: struct'-Einschränkung hinzufügen - diese sollte nicht für Referenztypen aufrufbar sein. – Keith

1

Die Signatur für das, was Sie suchen ist:

public class Reader 
{ 
    public static T Read<T>() 
    { 
    } 
} 

Sie müssen dies in einer Art zu platzieren. Es kann eine Instanz oder ein statisches Element sein.


Edit:

Es wird wie jedes andere Verfahren verwendet, außer Sie die generische Typargument explizit passieren müssen. Zum Beispiel:

byte mode = Reader.Read<byte>() 
+1

Einige Anwendungsbeispiele wären auch nett? –

+0

Ich würde gerne wissen, wie man etwas in der Reader-Klasse "zurückgibt". Könnten Sie bitte ein Beispiel geben? –

4

Dies ist eine Funktionsvorlage. Sie müssen eine Klasse in C#, aber so etwas wie:

public static class Utility 
{ 
    public static Type Read<Type>() 
    { 
     //Converted code to c# that returns a Type; 
    } 
} 

Sie wollen wahrscheinlich Einschränkungen für diesen Einsatz, wie zum Beispiel auf den Wert Typen zu begrenzen.

Sie können die Funktion wie folgt aufrufen:

Utility.Read<int>(); 
+0

Und einige Beispiele dafür, wie es heißt? –

1

Ich möchte nur darauf hinweisen, dass Ihr C++ - Beispiel voll von globalen Variablen ist, und etwas tut, das nicht sehr gut über generische Typen funktioniert, die anderen hier haben darauf hingewiesen heraus, wie man mit der eigentlichen Methodensignatur umgeht, aber anstatt diesen C++ - Code zu portieren, würde ich etwas nachbessern, das besser zum Stil von C# passt.

Befreien Sie sich von den Globalen.

0

Mein C++ ist sehr rostig, aber es sieht so aus, als liest man Werttypen aus einem Stream.

Sie können Generika als Referenztypen oder Werttypen definieren und eine leere Variable mit dem Schlüsselwort default initialisieren.

Sie sind auch besser dran, Ihren Stream als Parameter übergeben.

Beachten Sie auch, dass in C++ diese Vorlagen sind - Sie erhalten eine Kopie des für jeden verwendeten Typ kompilierten Codes. Dies schließt eine Referenzierung der C++ - Bibliothek von C# aus, da, wenn C++ kompiliert wird, dieser nicht notwendigerweise den Typ aufweist, nach dem der C# -Code kompiliert werden soll.

In C# ist nur eine Klasse kompiliert und kann extern referenziert werden.

0

Ich bin mir nicht ganz sicher, woher der Datenstrom kommt. Wenn es sich jedoch um einen nicht verwalteten Zeiger handelt, können Sie Folgendes tun.

public static T Read<T>(ref IntPtr ptr) 
    where T : struct { 
    var size = Marshal.SizeOf(typeof(T)); 
    var value = (T)Marshal.PtrToStructure(ptr, typeof(T)); 
    ptr = new IntPtr(ptr.ToInt64() + size); 
    return value; 
} 
Verwandte Themen