【问题标题】:C# Linq Select Problem in Method ChainC# Linq 在方法链中选择问题
【发布时间】:2011-01-28 00:34:00
【问题描述】:

注意_src继承IQueryable<U>,V继承new()

我写了以下语句,没有语法错误。

IQueryable<V> a = from s in _src where (s.Right - 1 == s.Left) select new V();

但如果我重新编写如下,Visual Studio 编辑器会在“选择”中报错

IQueryable<V> d = _src.Where(s => s.Right - 1 == s.Left).Select(s=> new V());

错误是:

The type arguments cannot be inferred from the usage. Try specifying the type arguments explicitly.
Candidates are:
  System.Collections.Generic.IEnumerable<V> Select<U,V>(this System.Collections.Generic.IEnumerable<U>, System.Func<U,V>) (in class Enumerable)
  System.Linq.IQueryable<V> Select<U,V>(this System.Linq.IQueryable<U>, System.Linq.Expressions.Expression<System.Func<U,V>>) (in class Queryable)

谁能解释一下这个现象,解决这个错误的方法是什么?

=== 编辑(2010-03-16 5:35pm)===

谢谢迈克二号。我也尝试了一个像你这样的简单例子。它有效,但这不适用于我的。我贴出的代码如下:

public class NSM<U, V> where U : IQueryable<U> where V : new()  
  {
    private U _src;
    public NSM(U source) { _src = source; }
    public IQueryable<V> LeafNodes
    {
      get
        {
          return from s in _src where (s.Right - 1 == s.Left) select new V();
        }
    }
  }

我希望将 LeafNodes 函数重写为 linq 方法链方法。有什么想法吗?

【问题讨论】:

  • 谢谢大家。第一个的等效语句是什么?
  • 除非 U 是具有 Right 和 Left 属性的东西,否则您添加的代码不会编译。所以它不能只是一个IQueryable&lt;U&gt;,除非有一个where U : ILeftRight或其他东西。
  • 感谢您更新的示例,我明白了。请参阅下面的更新答案。感谢您提供更多信息。
  • 谢谢大家。该解决方案有效,该示例清楚地阐明了问题。顺便问一下,Expression> 和 Func 有什么区别? "x => new V()" 的类型可以是其中任何一个?
  • 是的 x =&gt; new V() 可以是 Func&lt;X,V&gt;Expression&lt;Func&lt;X,V&gt;&gt;IQueryable 实现可以检查Expression 版本的内容并根据需要对其进行解释。这就是 LINQ to SQL 如何将 lambdas 更改为 SQL 查询。如需更好的解释,请参阅msdn.microsoft.com/en-us/library/bb397951.aspx

标签: c# linq select selector


【解决方案1】:

_src 的类型是什么?它直接实现IQueryable吗?我问是因为我可以得到一个简化的例子来说明你所展示的工作。

IQueryable< int > ints = Enumerable.Range( 4, 12 ).AsQueryable();

IQueryable< decimal > foo = from s in ints where s > 7 select s * 4.2m;

IQueryable< decimal > bar = ints.Where( s => s > 7 ).Select( s => s * 4.2m );

这两种选择都适合我。我认为如果编译器知道整数(或在您的情况下为 _src)是 IQueryable,那么它将调用正确的重载。还是我完全错过了什么?可能是我过于简单化了,遗漏了一些细节。

编辑:扩展它以使用新的示例代码并进行一些更改。

诀窍是Queryable.Select 接受Expression&lt;Func&lt;X, V&gt;&gt;Enumerable.Select 接受Func&lt;X,V&gt; 所以你只需要提供一个Expression 版本给Select

public interface ILeftRight
{
    int Right { get;}
    int Left { get; }
}

public class NSM<X, U, V> where U : IQueryable<X> where X : ILeftRight where V : new()  
{
    private readonly U _src;
    public NSM(U source) { _src = source; }
    public IQueryable<V> LeafNodes
    {
        get
        {
            //return from s in _src where (s.Right - 1 == s.Left) select new V();
            Expression< Func< X, V > > expression = s => new V();
            return _src.Where( s => s.Right - 1 == s.Left ).Select( expression );
        }
    }
}

或者来自原始代码

Expression<Func<X,V>> expression = s => new V();
IQueryable<V> d = _src.Where(s => s.Right - 1 == s.Left).Select(expression);

【讨论】:

    【解决方案2】:

    要解决编译器的歧义,请使用AsEnumerable() 函数

    src.AsEnumerable().Select(s => new V());
    

    或分配给 IQueryable

    IQueryable<V> x = src.AsEnumerable().Select(s => new V()).AsQueryable();
    

    【讨论】:

    • 但这将返回 IEnumerable 而不是 IQueryable。在不更改返回类型的情况下有什么解决方法?
    【解决方案3】:

    您遇到的问题是,在第二个示例中 Select 有两种不同的用途,并且您有适当的 using 语句来访问它们。编译器无法从该语句中找出您要使用哪个语句。如果不再需要,您必须使用更专业的调用来选择或删除使用,或者以其他方式明确您要使用哪个。

    【讨论】:

    • 如果我将“AsQueryable()”添加到 Select 中,如下所示:IQueryable d = _src.Where(s => s.Right - 1 == s.Left).AsQueryable() .Select(s=>新V());错误也是一样的。
    【解决方案4】:

    发生错误是因为编译器无法选择您要执行的方法:Select 扩展方法为IEnumerable&lt;T&gt;Select 扩展方法IQueryable&lt;T&gt;

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-11-20
      • 2014-12-18
      • 1970-01-01
      • 1970-01-01
      • 2010-09-12
      • 1970-01-01
      • 2014-07-19
      相关资源
      最近更新 更多