【问题标题】:Type inference infers in the scope of the class but not methods though they are just the same?类型推断是在类的范围内推断,但不是方法,尽管它们是一样的?
【发布时间】:2012-11-04 13:31:10
【问题描述】:

好吧,我一定是把标题弄错了。更多的代码,更少的文字:

public class Manager<T> where T : Control, new()
{
    void Manage()
    {
        Do(t => IsVisible(t));
    }

    bool IsVisible(T t)
    {
        return t.Visible;
    }

    S Do<S>(Func<T, S> operation)
    {
        return operation(new T());
    }
}

编译器对Do 很满意。它可以很容易地推断出T 类型。现在假设我有这个:

public static class Util
{
    static void Manage()
    {
        Do(t => IsVisible(t)); //wiggly line here
    }

    static bool IsVisible<T>(T t) where T : Control
    {
        return t.Visible;
    }

    static S Do<S, T>(Func<T, S> operation) where T : Control, new()
    {
        return operation(new T());
    }
}

编译器现在希望类型被显式类型化。这是我的想法:

在第一类中,T 很容易从 IsVisible 方法推断出来,该方法具有 T 重载,TManager 类中众所周知,没什么大不了的。但在第二种情况下,T 被指定为方法的通用约束,可能更难推断。好的。

但这也不起作用:

public static class Util
{
    static void Manage()
    {
        Do(t => IsVisible(t)); //still wiggly line
    }

    static bool IsVisible(Control t)
    {
        return t.Visible;
    }

    static S Do<S, T>(Func<T, S> operation) where T : Control, new()
    {
        return operation(new T());
    }
}
  1. 为什么编译器在最后一种情况下不推断T

  2. 更重要的是,最后一个案例与第一个案例有何不同?在第一种情况下,编译器必须从IsVisible 方法推断它,然后一直返回检查T 在包含IsVisible 的类中是什么,而在最后一种情况下,它在IsVisible 方法中很容易获得.所以我认为第三种情况比第一种更容易。

【问题讨论】:

    标签: c# c#-4.0 type-inference generic-constraints


    【解决方案1】:

    (第一种情况)

    编译器对 Do 很满意。它可以很容易地推断出 T 型。

    它根本不是在推断TT 是类的类型参数:

    public class Manager<T> where T : Control, new()
    

    (第二种情况)

    编译器现在希望类型被显式类型化。

    我假设您的意思是在管理代码中:

    Do(t => IsVisible(t))
    

    没错。 认为T的类型应该在这里?您希望编译器如何推断它?

    (第三种情况,其中方法为IsVisible(Control t)

    为什么编译器在最后一种情况下不推断 T?

    它不能仅从参数中做到这一点。听起来您希望它能够计算出 lambda 表达式的主体可以工作的每种类型……而类型推断根本无法以这种方式工作。不过,您可以轻松地为编译器提供足够的信息:

     Do((Control t) => IsVisible(t)); 
    

    更重要的是,最后一个案例与第一个案例有何不同?

    在第一种情况下,T 不是Do 方法的类型参数。编译器需要推断S,它可以从lambda表达式的返回类型中完成。它不需要对T 执行任何推断,因为这已经是“已知的”。 (它仍然是通用的,但它不是需要为该方法调用推断的东西。)首先在构造Manager 的实例时需要提供T 的类型,所以它有效地推动了这个决定。

    有关类型推断的所有详细信息,请参阅 C# 4 规范的第 7.5.2 节(或 C# 3 或 C# 5 规范中的等效部分)。不过我建议先喝一杯浓咖啡:)

    【讨论】:

    • 乔恩很好的答案。真正启发我的答案是T 在第一种情况下没有被推断出来。我知道编译器从第二种情况推断类型有点苛刻,但我确实认为如果 C# 从第三种情况推断类型会更好。欢迎您的工作。谢谢你
    • 乔恩,你不认为它是 C# 的一个弱点,它不能从我的第三种情况推断类型吗?如果IsVisibles 重载,肯定会出现很多歧义,但至少这可能会导致编译时出现歧义错误,就像在其他情况下一样
    • @nawfal:不是这样。鉴于类型推断规则已经如此复杂,我不想让它们变得更复杂。如果您认为您可以做得更好,我建议您只需尝试 写出编译第三种情况所需的规则。如果你能想出一个不是非常复杂的公式,我相信 C# 团队很乐意听取你的意见。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-25
    • 1970-01-01
    • 2019-10-11
    • 1970-01-01
    • 2018-04-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多