Calling an overloaded method with a shared property causes incorrect overloading
I have a base filter class that stores the parameter name string
and general value T
. The filter has a method Write(writer As IWriter)
that will write the content of the filter to an HTML page. The method Write
has two overloads: one that takes two strings and takes a string and an object. This allows me to specify the lines automatically.
The problem is, when called writer.Write(ParameterName, Value)
and T
is string
, it invokes the overload on string / object, not string / string! If I call the Write method on writer
directly, it works as expected.
Here's an SSCE in C #. I tested this in both VB and C # and found the same problem
void Main() {
FooWriter writer = new FooWriter();
Filter<string> f = new Filter<string>() {ParameterName = "param", Value = "value"};
f.Write(writer); //Outputs wrote w/ object
writer.Write(f.ParameterName, f.Value); //Outputs wrote w/ string
}
class FooWriter {
public void Write(string name, object value) {
Console.WriteLine("wrote w/ object");
}
public void Write(string name, string value) {
Console.WriteLine("wrote w/ string");
}
}
class Filter<T> {
public string ParameterName {get; set;}
public T Value {get; set;}
public void Write(FooWriter writer) {
writer.Write(ParameterName, Value);
}
}
source to share
The problem is that when I call writer.Write (ParameterName, Value) and T is a string, it calls the overload for string / object, not string / string!
Yes, it is expected - or rather, it behaves as indicated. The compiler usually chooses overloading based on the types of the compile-time arguments. There is no implicit conversion from T
to string
, so writer.Write(ParameterName, Value)
overloading is the only applicable call candidate Write(string, object)
.
If you want it to do overload resolution at runtime, you need to use dynamic typing. For example:
public void Write(FooWriter writer) {
// Force overload resolution at execution-time, with the execution-time type of
// Value.
dynamic d = Value;
writer.Write(ParameterName, d);
}
Note that this may still behave unpredictably - if it Value
is null, it will be equivalent to a call writer.Write(ParameterName, null)
that will use the "better" member of the function - here writer.Write(string, string)
- even if the type T
object
!
source to share