【问题标题】:Open generic type arguments cannot be inferred from the usage无法从用法中推断出开放的泛型类型参数
【发布时间】:2016-11-15 21:51:45
【问题描述】:

在这个问题中,当提到编译器时,我实际上指的是 Roslyn 编译器。使用 IntelliSense 时出现问题,推测是同一个编译器。

出于演示目的和完整性,使用了以下类(使用带有 C# 6.0 和 .NET 4.6.1 的 Visual Studio 2015):

public class A
{
    public IEnumerable<B> B { get; set; }
}
public class B
{
    public IEnumerable<C> C { get; set; }
}
public class C { }
public class Helper<T> { }

看下面的扩展方法:

public static void FooBar<T1, T2>(
    this Helper<IEnumerable<T1>> helper,
    Expression<Func<T1, IEnumerable<T2>>> expression) { ... }

编译器能够在这样消费时推断它:

Helper<IEnumerable<B>> helper = ...;
helper.FooBar(l => l.C); //T1 is B and T2 is C

还请看这个重载的扩展方法:

public static void FooBar<T1, T2, T3>(
    this Helper<T1> helper,
    Expression<Func<T1, IEnumerable<T2>>> expression1,
    Expression<Func<T2, IEnumerable<T3>>> expression2) { ... }

当这样输入T1时,编译器不能推断:

Helper<A> helper = ...;
helper.FooBar(l => l. //compiler/IntelliSense cannot infer that T1 is A

这个截图示例将描述更多我的意思无法推断

当我将鼠标悬停在扩展方法上时,我也会收到此错误消息(我已将 &lt;&gt; 字符分别替换为 [],因为 StackOverflow 不能格式化那些引用):

无法推断方法 'FooBar[T1,T2](this Helper[IEnumerable[T1]], Expression[Func[T1, IEnumerable[T2]]])' 的类型参数 从用法上。尝试明确指定类型参数。

但是当像这样手动完成它时:

helper.FooBar(l => l.B, l => l.C); //compiler infers that T1 is A, T2 is B and T3 is C

编译器很高兴。

为什么编译器/IntelliSense(或 Visual Studio 的自动完成功能)无法识别 T1 并希望我在开始输入时明确指定类型参数?

请注意,如果我在示例中的所有位置都省略了 IEnumerable&lt;&gt;,编译器可以在键入时愉快地推断出所有内容。
手动输入l =&gt; l.B 后,编译器也很高兴。然后它知道T1A,因此您可以在IntelliSense 的帮助下表达最后一个参数。

【问题讨论】:

  • 当您说“编译器无法推断 T1 是 A”时,您实际上是指 IDE 的自动完成功能,对吧?
  • 整个 Roslyn 项目背后的想法之一是拥有一个既能编译代码又能在 IntelliSense 中运行的单一编译器。然而,在某些方面,IntelliSense 与编译东西有点不同(我认为需要更多信息)。所以我们仍然有一些情况下 IntelliSense 只是保释我们,而代码仍然可以愉快地编译:-(
  • 我更想说这是“设计”的限制:)
  • @StefanSteinegger 我希望专家确认这是否是一个合法的错误,或者这是一个有意设计受限的功能。

标签: c# .net generics visual-studio-2015 roslyn


【解决方案1】:

我发现你的问题很有趣,因为我使用的是 VS 2015,我想我也可以尝试一下。我遇到了和你一样的错误,所以我想这可能是一个 VS 错误,因为在其他版本中它可以正常工作。

这是我的错误:

而且我在 CTRL + SPACE 上也得到 没有建议

编辑:

可以看到类似的错误here

所以,由于在旧版本的 VS 中这是可行的,所以这就是它可以被视为错误的原因。

【讨论】:

    【解决方案2】:

    正如我所说,我有 same problem.(而 here 是错误报告)
    它与表达式或 IEnumerable 无关。
    这是一个简化的例子

    using System;
    
    namespace ConsoleApplicationExpressionTree
    {
    
        public static class Extentions
        {
            static void Main() { }
            static void AMethod(string[] args)
            {
                SetValue(new Customer(), e => e.Name   /*type here */, "TheName");
    
            }
    
            public static void SetValue<TEntity, TProperty>(TEntity instance, Func<TEntity, TProperty> expression, TProperty newValue)
            {
    
            }
        }
        public class Customer
        {
            public string Name { get; set; }
            public int Age { get; set; }
        }
    }
    

    我刚刚注意到,如果你从方法中删除第三个参数,它会起作用!!!

    using System;
    
    namespace ConsoleApplicationExpressionTree
    {
    
        public static class Extentions
        {
            static void Main() { }
            static void AMethod(string[] args)
            {
                SetValue(new Customer(), e => e.Name   /*type here */);
    
            }
    
            public static void SetValue<TEntity, TProperty>(TEntity instance, Func<TEntity, TProperty> expression)
            {
    
            }
        }
        public class Customer
        {
            public string Name { get; set; }
            public int Age { get; set; }
        }
    }
    

    因此,如果您非常幸运,您可以通过调整参数来修复当前示例。
    如果没有,你只需要等待MS修复它......

    【讨论】:

      【解决方案3】:

      如果我的理解正确,那么 VS2013 中的一切对我来说都按预期工作:

      你的第一个案例:

      你的第二种情况:

      我开始输入l.,IntelliSense 显示l 有一个可以使用的属性B。因此,如果我是对的并且它在 VS2013正确推断,而在 VS2015 中它不正确推断,那么这绝对是 VS2015 IntelliSense 中的错误,可以报告给 Microsoft。

      【讨论】:

      • 您正在使用第一个重载(带有&lt;T1, T2&gt; 作为开放泛型类型参数的重载)。这 确实VS2015 中工作(正如我在我的问题中提到的那样)。问题是第二个重载(带有&lt;T1, T2, T3&gt; 的那个)在VS2015 中不起作用。这在 VS2013 中有效吗?如果它在 VS2013确实 工作,您能否提供一个屏幕截图?
      • 我不确定我是否完全理解你的问题是什么,但对我来说,无论表达式数量如何,它都能正确显示 Helper&lt;A&gt;Helper&lt;IEnumerable&lt;A&gt;&gt; 的提示。请查看视频:1) take.ms/Okfxx 2) take.ms/c5YZB 但是,如果您在扩展方法中指定 Helper&lt;A&gt; 并在您的方法中指定 Helper&lt;IEnumerable&lt;A&gt;&gt; 它会认为 AIEnumerable&lt;A&gt; 所以不会除非您采取First() 或其他方式,否则向您显示提示。
      • 在您提供的屏幕截图中,您使用的是 first 扩展方法(因为它是Helper&lt;IEnumerable&lt;T&gt;&gt;)。所以我问你 second 扩展方法是否也适用于 VS2013(使用FooBarHelper&lt;T&gt;)。如果它有效,那么您能否提供一个屏幕截图证明它适用于第二种扩展方法(重载)。
      • 我明白了,我可以确认您在 VS2013 中使用了 second 扩展方法(正如我所描述的那样,这是我的问题题)。似乎 VS2013IntelliSense 可以在键入时推断类型,而 VS2015IntelliSense 不能。所以问题仍然存在,如果这确实是 bug,还是 design有意缺失功能?
      • 好吧,如果 IntelliSense suggests 你在 VS2013 中的正确属性并且 不建议 VS2015 什么时候应该,特别是如果你告诉它允许你编译之后你完成输入,但没有帮助你正在打字,那么这对我来说听起来像是一个明显的错误。我看不出有任何理由故意做出这种不舒服和令人困惑的行为。当然我可能错了,但这样的“改进”对我来说似乎很奇怪。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-10-11
      • 1970-01-01
      • 2016-05-09
      • 1970-01-01
      • 1970-01-01
      • 2023-03-08
      • 1970-01-01
      相关资源
      最近更新 更多