C# 使用泛型属性调用重载方法调用错误的重载

C# 使用泛型属性调用重载方法调用错误的重载,c#,vb.net,generics,overloading,C#,Vb.net,Generics,Overloading,我有一个基本的过滤器类,它存储一个字符串参数名和一个通用的T值。过滤器有一个方法Write(writer作为IWriter),它将过滤器的内容写入HTML页面。Write方法有两个重载,一个重载接受两个字符串,另一个重载接受一个字符串和一个对象。这使我可以自动引用字符串 问题是,当我调用writer.Write(ParameterName,Value)并且T是string时,它调用string/object的重载,而不是string/string!如果我直接调用编写器上的Write方法,它将按预

我有一个基本的过滤器类,它存储一个
字符串
参数名和一个通用的
T
值。过滤器有一个方法
Write(writer作为IWriter)
,它将过滤器的内容写入HTML页面。
Write
方法有两个重载,一个重载接受两个字符串,另一个重载接受一个字符串和一个对象。这使我可以自动引用字符串

问题是,当我调用
writer.Write(ParameterName,Value)
并且
T
string
时,它调用string/object的重载,而不是string/string!如果我直接调用
编写器上的Write方法,它将按预期工作

这是C#中的SSCE。我在VB和C#中测试了这一点,发现了同样的问题

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);
    }
}
void Main(){
FooWriter writer=新FooWriter();
Filter f=new Filter(){ParameterName=“param”,Value=“Value”};
f、 Write(writer);//使用对象写入的输出
writer.Write(f.ParameterName,f.Value);//用字符串写入的输出
}
班级编剧{
公共无效写入(字符串名称、对象值){
Console.WriteLine(“写入对象”);
}
公共无效写入(字符串名称、字符串值){
Console.WriteLine(“写入了字符串”);
}
}
类过滤器{
公共字符串参数名称{get;set;}
公共T值{get;set;}
公共无效写入(FooWriter){
Write.Write(参数名称、值);
}
}
问题是,当我调用writer.Write(ParameterName,Value)并且T是字符串时,它调用字符串/对象的重载,而不是字符串/字符串

是的,这是预期的——或者说,它的行为符合规定。编译器通常根据参数的编译时类型选择重载。没有从
T
string
的隐式转换,因此调用
writer.Write(ParameterName,Value)
的唯一适用候选对象是
Write(string,object)
重载

如果希望它在执行时执行重载解析,则需要使用动态类型。例如:

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

请注意,这仍然可能会出现意外的行为-如果
Value
为null,那么它将相当于调用
writer.Write(ParameterName,null)
,这将使用“better”函数成员-在这里
writer.Write(string,string)
-即使
T
的类型是
object

为什么编译时类型是
T
对象,而不是字符串?当我编译时,我认为编译器“神奇地”用它们的具体等价物替换了我程序中的所有泛型。@just.other.programmer:T
的编译时类型只是
T
。。。但是有一个
T
object
的隐式转换,而不是从
T
string
Filter
只编译一次-基本上,您需要更新对泛型如何工作的理解。对于
writer.Write(f.ParameterName,f.Value)
,编译器知道
T
是一个字符串。这与声明
过滤器f
有关,我假设?关于编译器在这两种情况下的实际操作有什么好的阅读材料吗?@just.other.程序员:是的,因为
f
的类型是
Filter
。将其与编译器编译
Filter
的时间点进行比较-它将其转换为IL一次,即使
Filter
可以在多个位置使用不同类型的
T
。至于最好的阅读材料。。。我完全推荐C#规格。我不知道C#deeph(我自己的书)在这方面是否有帮助——我希望如此,但我不能肯定。你知道如何强制执行时间过载解决方案吗?使用
Dim d=Value
(粗略的VB动态等价物)不起作用。