Help with generic method definition containing BitConverter.GetBytes

D

DaveD

Can anyone help me get this compiled ?

void Write<T>(T val) {
byte[] bytes = BitConverter.GetBytes(val);
Array.Reverse(bytes);
writer.Write(bytes);
}

The problem is that for T=bool, BitConverter.GetBytes(bool) won't
compile. In C++ I would have created an explicit instantiation like
this

void Write<bool>( bool val ) { writer.Write((byte)(val?
1:0)); } //

I know that we don't have this capability in C#, so any other ideas
welcome please. I can't see a "where" constraint that will work for
me, unless I create my own wrapper classes (don't go there please!).

Thanks and regards
Dave Dawkins
 
J

Jon Skeet [C# MVP]

DaveD said:
Can anyone help me get this compiled ?

void Write<T>(T val) {
byte[] bytes = BitConverter.GetBytes(val);
Array.Reverse(bytes);
writer.Write(bytes);
}

The problem is that for T=bool, BitConverter.GetBytes(bool) won't
compile. In C++ I would have created an explicit instantiation like
this

void Write<bool>( bool val ) { writer.Write((byte)(val?
1:0)); } //

As far as I'm aware in C++ you wouldn't have really needed to, as the
templating system would have taken care of it for you.
I know that we don't have this capability in C#, so any other ideas
welcome please. I can't see a "where" constraint that will work for
me, unless I create my own wrapper classes (don't go there please!).

No, basically there's no way of doing this with .NET generics. There's
a big difference between .NET generics (where the generic method/type
resolves all calls including overloads at compile-time) and C++
templates (which are sort of very smart macros in many ways).

Sorry, but it can't be done. You could use reflection of course, and
that can be optimised in various ways to reduce the performance penalty
significantly, but it will still be slightly "icky".
 
M

Marc Gravell

This problem isn't well suited to generics. You could use reflection,
but that will be slow unless you use Delegate.CreateDelegate (and
cache it). I wonder if overloads wouldn't be more suitable than
generics here?
 
J

Jeroen Mostert

DaveD said:
Can anyone help me get this compiled ?

void Write<T>(T val) {
byte[] bytes = BitConverter.GetBytes(val);
Array.Reverse(bytes);
writer.Write(bytes);
}

The problem is that for T=bool, BitConverter.GetBytes(bool) won't
compile.

It won't compile for any T. The only .GetBytes() overload that can legally
be invoked for a generic T would take a parameter of Object type, but
there's no such overload.
In C++ I would have created an explicit instantiation like this

void Write<bool>( bool val ) { writer.Write((byte)(val?
1:0)); } //

I know that we don't have this capability in C#, so any other ideas
welcome please.

The most straightforward way, tedious as it is, is to write out the
overloads yourself:

void Write(byte[] val) {
Array.Reverse(val);
writer.Write(val);
}

void Write(bool val) {
Write(BitConverter.GetBytes(val));
}

void Write(int val) {
Write(BitConverter.GetBytes(val));
}

Etcetera, etcetera. Even though all functions are "the same", they're not
really. C++ templates can exploit textual similarity, C# generics cannot.

As others have suggested, reflection is an option here (getting the proper
overload for .GetBytes()) dynamically) but I wouldn't bother. The resulting
code will be slower and certainly not clearer, even if it might be somewhat
shorter. If you take the step of optimizing the reflection (through
lightweight code generation for example) the code becomes even more unclear,
and might actually end up longer.
 
B

Ben Voigt [C++ MVP]

DaveD said:
Can anyone help me get this compiled ?

void Write<T>(T val) {
byte[] bytes = BitConverter.GetBytes(val);
Array.Reverse(bytes);
writer.Write(bytes);
}

The problem is that for T=bool, BitConverter.GetBytes(bool) won't
compile. In C++ I would have created an explicit instantiation like
this

void Write<bool>( bool val ) { writer.Write((byte)(val?
1:0)); } //

I know that we don't have this capability in C#, so any other ideas
welcome please. I can't see a "where" constraint that will work for
me, unless I create my own wrapper classes (don't go there please!).

Use generics at class level, so you can have per-type fields.

Then have a field of delegate type Converter<T, byte[]>. You can then
assign a different implementation for each T. BitConverter.GetBytes can be
used for those T where they are appropriate, you will still need to
explicitly assign the delegate field for each T separately.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top