【问题标题】:Calling overloaded method with generic property calls wrong overload使用泛型属性调用重载方法调用错误的重载
【发布时间】:2014-12-15 17:17:56
【问题描述】:

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

问题是,当我调用writer.Write(ParameterName, Value)Tstring 时,它调用的是字符串/对象的重载,而不是字符串/字符串!如果我直接在writer 上调用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);
    }
}

【问题讨论】:

    标签: c# vb.net generics overloading


    【解决方案1】:

    问题是,当我调用 writer.Write(ParameterName, Value) 并且 T 是一个字符串时,它调用的是字符串/对象的重载,而不是字符串/字符串!

    是的,这是意料之中的 - 或者更确切地说,它的行为符合指定。编译器通常根据参数的 compile-time 类型来选择重载。没有从Tstring 的隐式转换,因此调用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 为空,那么它等效于调用 writer.Write(ParameterName, null) 将使用“更好”的函数成员 - 这里是 writer.Write(string, string) - 即使 @987654329 的类型@是object

    【讨论】:

    • 为什么T对象的编译时类型不是字符串?我认为编译器在我编译时用它们的具体等价物“神奇地替换”了我程序中的所有泛型。
    • @just.another.programmer:T 的编译时类型只是 T... 但有 Tobject 的隐式转换,但不是来自 @ 987654336@ 至stringFilter&lt;T&gt; 只编译一次 - 你需要更新你对泛型工作原理的理解,基本上。
    • 对于writer.Write(f.ParameterName, f.Value),编译器知道T是一个字符串。这与我假设的 Filter&lt;string&gt; f 声明有关吗?关于编译器在这两种情况下实际做了什么的任何好的阅读材料?
    • @just.another.programmer:是的,因为f的类型是Filter&lt;string&gt;。将其与编译器编译 Filter&lt;T&gt; 的点进行比较 - 它会将其转换为 IL once,即使 Filter&lt;T&gt; 可以在多个位置使用 T 的不同类型。至于最好的阅读材料……我会彻底推荐 C# 规范。我不知道 C# in Depth(我自己的书)是否会对这本书有所帮助 - 我希望如此,但我不能肯定地说。
    • 你知道如何强制执行时间重载解决吗?使用Dim d = Value(VB 的粗略等效的动态)不起作用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-12
    相关资源
    最近更新 更多