Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic method can't call correct overload

NB: I'm using the Mono environment, if that makes a difference.

I'm writing some tests, and to help with that I have the following generic method:

static MemoryStream writeValue<T>(T inVal)
{
  MemoryStream ms = new MemoryStream();
  BinaryWriter bw = new BinaryWriter(ms);
  encode_any(bw, inVal);
  return ms;
}

The idea is that this will call one of my encode_any overloads, which delegate to type-specific methods:

public static void encode_any(BinaryWriter writer, Int32 val) { encode_int32(writer, val); }
public static void encode_any(BinaryWriter writer, Int64 val) { encode_int64(writer, val); }
public static void encode_any(BinaryWriter writer, Float val) { encode_float(writer, val); }
...etc...
public static void encode_any(BinaryWriter writer, bool val) { encode_bool(writer, val); }

The reason I want to do this is so that I can call the right implementation in each case without needing several versions of 'writeValue', and without inspecting the run-time type of each item before choosing which encode_ function to call.

However it appears that the compiler is attempting to resolve the overload of writeValue without knowing what type T will be, so I get this error:

error CS1502: The best overloaded method match for 'BinarySerialiser.encode_any(System.IO.BinaryWriter, bool)' has some invalid arguments error CS1503: Argument '#2' cannot convert 'T' expression to type 'bool'

I notice that this is not specifically about bool - if I rearrange the order of my encode_any functions, it always attempts to use the last one. Maybe it just tries each one and then only emits the error when it runs out of alternatives.

This sort of code would work fine under C++ where writeValue is only compiled when T is known, but that doesn't appear to be the case here, and I suspect this is because C# handles generic types at runtime.

Can I change my approach to make this work, and if so how?

like image 512
Kylotan Avatar asked Aug 22 '11 13:08

Kylotan


1 Answers

This is not C++ but C#. That means, the code you have isn't working, because in a generic class in C# you have access to all known members of the generic type parameters. Which members are known is solely determined by the constraints you put on the generic type parameters. IIRC, in C++ it is a bit different.
Anyway, in your case, there are no constraints on T, so the compiler knows nothing about that generic parameter. However, there is no constraint that would allow you to do, what you want to do.
If you were using .NET 4.0, you could use the new dynamic keyword:

static MemoryStream writeValue<T>(T inVal)
{
  MemoryStream ms = new MemoryStream();
  BinaryWriter bw = new BinaryWriter(ms);
  dynamic dynamicValue = inVal;
  encode_any(bw, dynamicValue);
  return ms;
}

Because you are using Mono, I don't think you can use this as Mono hasn't implemented this keyword yet.
It looks like Mono already implemented the DLR, see link from paolo below.

like image 164
Daniel Hilgarth Avatar answered Nov 02 '22 16:11

Daniel Hilgarth