C#:如何制作Type泛型方法(byte / word / dword)?

时间:2009-04-19 17:57:52

标签: c# generics

我是仿制药的新手,我在C#中找到的就是List [T] - 没有别的。

这是我必须在C#中翻译的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;
}   

它被称为

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

问题:如何使用C#Generics做到这一点?

7 个答案:

答案 0 :(得分:4)

这是一个功能模板。你需要一个C#类,但是像:

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

您可能希望对此使用约束,例如限制值类型。

你可以这样调用这个函数:

Utility.Read<int>();

答案 1 :(得分:4)

您的代码似乎模仿ReadInt16类的ReadInt32ReadInt64BinaryReader方法。

如果不了解全局变量,很难提供重写。假设流是一个字节数组,以下代码将起作用。

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];
}

答案 2 :(得分:1)

您正在寻找的签名是:

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

您需要将其放入一个类型中。它可以是实例或静态成员。


编辑:

除了必须显式传递泛型类型参数外,它的使用方式与其他方法类似。例如:

byte mode = Reader.Read<byte>()

答案 3 :(得分:1)

查看MSDN上的Introduction to C# Generics文章。之后应该是不言自明的......

答案 4 :(得分:1)

我只是想指出你的C ++示例充满了全局变量,并且做了一些在泛型类型中不能很好地工作的东西,其他人已经指出了如何处理实际的方法签名,而不是移植那个C ++代码,我会更好地修改一些符合C#风格的东西。

摆脱全局变种。

答案 5 :(得分:0)

我的C ++非常生疏,但看起来你正在从流中读取值类型。

您可以将泛型限制为引用类型或值类型,并且可以使用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;
}

您最好将您的信息流作为参数传递。

还要记住,在C ++中这些是模板 - 您将获得为所使用的每种类型编译的代码的副本。这排除了引用C#中的C ++库,因为在编译C ++时,它不一定具有C#代码要求编译的类型。

在C#中只编译了一个类,可以在外部引用它。

答案 6 :(得分:0)

我不完全确定您的数据流来自哪里。但是,如果它是一个非托管指针,您可以执行以下操作。

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