General method cannot cause proper overload

NB: I use the Mono environment if that matters.

I am writing some tests, and to help with this, I have the following general 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 cause one of my encode_any overloads, which are delegated to methods like:

 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 because I can invoke the correct implementation in each case without having to use multiple versions of "writeValue" and without checking the runtime type of each element before choosing which function to call encode_.

However, it seems that the compiler is trying to resolve writeValue overload, not knowing what type T will be, so I get this error:

error CS1502: best overloaded method matching for 'BinarySerialiser.encode_any (System.IO.BinaryWriter, bool)' has some invalid arguments error CS1503: argument '# 2' could not convert the expression 'T' for input 'bool'

I notice that this does not apply specifically to bool - if I change the order of my encode_any functions, it always tries to use the latter. Perhaps he simply tries each one and then throws an error when her alternatives run out.

This type of code will work fine in C ++, where writeValue only compiles when T is known, but it doesn't look like it here, and I suspect that this is because C # handles generic types at runtime.

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

+6
source share
2 answers

This is not C ++, but C #. This means that the code that you have does not work, because in a generic class in C # you have access to all known members of type parameter parameters. Which members are known is determined only by the constraints that you enter into the type type parameters. IIRC, in C ++ this is a little different.
In any case, in your case there are no restrictions on T , so the compiler does not know anything about this general parameter. However, there are no restrictions that will allow you to do what you want to do.
If you used .NET 4.0, you can 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; } 

Since you are using Mono, I do not think you can use this, since Mono has not yet implemented this keyword. It seems that Mono has already implemented DLR, see the link from paolo below.

+8
source

Your problem is that overload resolution is performed at compile time rather than run time - in this case, on the following line:

 encode_any(bw, inVal); 

inVal has no type restrictions other than inVal (or can be boxed) for an object, therefore only overloads that take an object to allow overloading are taken into account.

See also General Overload Resolution

My approach would probably be to create an overload of encode_any that takes an object and encode_any out which method to call at runtime.

+1
source

Source: https://habr.com/ru/post/895589/


All Articles