tags:

views:

1351

answers:

7

Hello,

I'm new to generics and all I could find in C# is List[T] - nothing else.

This is the C++ code I have to translate in 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;
}

Its called like that

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

Question:How to do that with C# Generics?

+1  A: 

The signature for what you're looking for is:

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

You need to place this into a type. It can be an instance or static member.


Edit:

It is used like any other method except you have to pass the generic type argument explicitly. For Example:

byte mode = Reader.Read<byte>()
__grover
Some usage examples would be nice too?
Binary Worrier
I'd like to know how to "return" something in the Reader class.Could you provide an example,please?
John
+4  A: 

This is a function template. You need a class in C#, but something like:

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

You'll probably want to use constraints for this, such as limiting to value-types.

You can call the function like this:

Utility.Read<int>();
jfclavette
And some samples of how it's called?
Binary Worrier
+1  A: 

Have a look at the Introduction to C# Generics article on MSDN. It should be self-explanatory after that...

sgreeve
+1  A: 

I just want to point out that your C++ example is full of global variables, and does something that doesn't work very well across generic types, the others here have pointed out how to handle the actual method signature, but instead of porting that C++ code, I'd rework into something that fits the style of C# better.

Get rid of the globals.

FlySwat
A: 

My C++ is very rusty, but it looks like you're reading value types from a stream.

You can restrict generics to be reference types or value types, and you can initialise an empty variable with the default keyword.

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

You're also better off passing your stream in as a parameter.

Also bear in mind that in C++ these are templates - you will get a copy of the code compiled for each type used. This rules out referencing the C++ library from C#, as when the C++ is compiled it doesn't necessarily have the type that the C# code is asking for compiled.

In C# there is only one class compiled, and it can be referenced externally.

Keith
+4  A: 

Your code seems to mimic the ReadInt16, ReadInt32 and ReadInt64 methods of the BinaryReader class.

It's hard to provide a rewrite without knowledge about your global variables. Assuming that stream is a byte array the following code would work.

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];
}
Simon Svensson
Nice solution (+1). I'd add a `where T:struct` restriction - this shouldn't be callable for reference types.
Keith
A: 

I'm not entirely sure where you're data stream is coming from. However, if it's an unmanaged pointer you can do the following.

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