2009-04-19 6 views
1

Je suis novice dans le domaine des génériques et tout ce que j'ai pu trouver dans C# is List [T] - rien d'autre.C#: Comment faire une méthode générique Type (octet/mot/dword)?

Ceci est le code C++, je dois traduire en 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; 
} 

Son appelé comme ça

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

Question: Comment faire avec C# Generics?

+0

"... le code C++ que je dois traduire en C# ..." Pourquoi? Vous pouvez appeler votre code C++ existant à partir de C# de plusieurs façons. Puisque vous utilisez des modèles, C++/CLI sera probablement le moyen le plus simple pour ce cas particulier. –

Répondre

4

Votre code semble imiter les méthodes ReadInt16, ReadInt32 et ReadInt64 de la classe BinaryReader.

Il est difficile de fournir une réécriture sans connaissance de vos variables globales. En supposant que ce flux est un tableau d'octets, le code suivant fonctionnerait.

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

Belle solution (+1). J'ajouterais une restriction 'où T: struct' - cela ne devrait pas être appelable pour les types de référence. – Keith

1

La signature de ce que vous cherchez est:

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

Vous devez placer cela dans un type. Ce peut être une instance ou un membre statique.


Edit:

Il est utilisé comme toute autre méthode, sauf que vous devez passer explicitement l'argument de type générique. Par exemple:

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

Certains exemples d'utilisation seraient bien aussi? –

+0

Je voudrais savoir comment "retourner" quelque chose dans la classe Reader. Pouvez-vous donner un exemple, s'il vous plaît? –

4

Ceci est un modèle de fonction. Vous avez besoin d'une classe en C#, mais quelque chose comme:

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

Vous voudrez probablement utiliser des contraintes pour cela, comme la limitation à des types de valeur.

Vous pouvez appeler la fonction comme ceci:

Utility.Read<int>(); 
+0

Et quelques exemples de comment ça s'appelle? –

1

Je veux juste souligner que votre exemple C++ est plein de variables globales, et fait quelque chose qui ne fonctionne pas très bien à travers les types génériques, les autres ici ont pointé comment gérer la signature de la méthode, mais au lieu de porter ce code C++, je voudrais retravailler quelque chose qui correspond mieux au style de C#.

Débarrassez-vous des globales.

0

Mon C++ est très rouillé, mais il semble que vous lisiez des types de valeur à partir d'un flux.

Vous pouvez limiter les types génériques à des types de référence ou à des types de valeur et vous pouvez initialiser une variable vide avec le mot clé default.

public T Read<T>(Stream input) 
    where T:struct //forces T to be a value type 
{ 
    T returnValue = default(T); //init a return value 
    int index = input.Position; 

    //your conversion here 

    return returnValue; 
} 

Vous avez également intérêt à transmettre votre flux en tant que paramètre.

Gardez également à l'esprit qu'en C++ ce sont des modèles - vous obtiendrez une copie du code compilé pour chaque type utilisé. Cela exclut la référence à la bibliothèque C++ de C#, car lorsque le C++ est compilé, il n'a pas nécessairement le type que le code C# demande de compiler.

En C#, une seule classe est compilée, et elle peut être référencée de manière externe.

0

Je ne suis pas tout à fait sûr d'où vient le flux de données. Toutefois, s'il s'agit d'un pointeur non géré, vous pouvez effectuer les opérations suivantes.

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; 
} 
Questions connexes