如果我将 IQueryable 转换为 IEnumerable 然后调用 Linq 扩展方法,将调用哪个实现?
考虑以下代码:
IQueryable<T> queryable;
// something to instantiate queryable
var enumerable = (IEnumerable<T>) queryable;
var filtered = enumerable.Where(i => i > 3);
在最后一行中,哪个扩展方法被调用?
是 IEnumerable
吗?或者是否会调用 IQueryable
因为实际实现显然仍然是可查询的?
据推测,理想的情况是调用 IQueryable 版本,就像正常的多态性将始终使用更具体的覆盖一样。
但在 Visual Studio 中,当我右键单击Where 方法并“转到定义”时,我会进入 IEnumerable 版本,从视觉角度来看,这是有意义的。
我主要担心的是,如果在我的应用程序中的某个地方我使用 Linq to NHibernate 来获取 Queryable,但我使用使用更通用的 IEnumerable 签名的接口来传递它,我将失去延迟数据库执行的奇迹!
编辑:事实证明,正如 Iridium 所指出的那样,它是被调用的 Enumerable 版本,
public class Program
{
static void Main(string[] args)
{
var myString2 = new MyString2();
var myString = (MyString)myString2;
Console.WriteLine(myString.Method());
Console.ReadLine();
}
}
public class MyString {}
public class MyString2 : MyString {}
public static class ExtensionMethods
{
public static string Method(this MyString instance)
{
return "MyString method";
}
public static string Method(this MyString2 instance)
{
return "MyString2 method";
}
}
输出是“MyString 方法”。
Considering the following code:
IQueryable<T> queryable;
// something to instantiate queryable
var enumerable = (IEnumerable<T>) queryable;
var filtered = enumerable.Where(i => i > 3);
In the final line, which extension method gets called?
Is it IEnumerable<T>.Where(...)
? Or will IQueryable<T>.Where(...)
be called because the actual implementation is still obviously a queryable?
Presumably the ideal would be for the IQueryable version to be called, in the same way that normal polymorphism will always use the more specific override.
In Visual Studio though when I right-click on the Where method and "Go to Definition" I'm taken to the IEnumerable version, which kind of makes sense from a visual point-of-view.
My main concern is that if somewhere in my app I use Linq to NHibernate to get a Queryable, but I pass it around using an interface that uses the more general IEnumerable signature, I'll lose the wonders of deferred database execution!
Edit: It turns out that, as Iridium has pointed out, it's the Enumerable version that gets called
public class Program
{
static void Main(string[] args)
{
var myString2 = new MyString2();
var myString = (MyString)myString2;
Console.WriteLine(myString.Method());
Console.ReadLine();
}
}
public class MyString {}
public class MyString2 : MyString {}
public static class ExtensionMethods
{
public static string Method(this MyString instance)
{
return "MyString method";
}
public static string Method(this MyString2 instance)
{
return "MyString2 method";
}
}
The output is "MyString method".
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
当前接受的答案涉及虚拟方法,而不是扩展方法。
如果您将 IQueryable 转换为 IEnumerable,然后调用扩展方法之一(例如问题中的Where(...)),则将调用 Enumerable 版本上的扩展方法,而不是 Queryable 版本。
The currently accepted answer deals with virtual methods, not extension methods.
If you cast an IQueryable to an IEnumerable and then call one of the extension methods (e.g. Where(...) in your question), then the one on Enumerable version will be called, not the Queryable one.
当您运行这个简单的程序时,它会解释重载是如何工作的:)。答案是底层类型的方法将被调用。对于
IQueryable
和IEnumerable
应该以相同的方式工作;也就是说,原始对象的方法将被调用,因为即使我们将其转换为其他内容,实际实现也是原始类型。但是,当存在扩展方法时,将使用所引用对象的扩展方法,因此在这种情况下,它取决于扩展方法中的逻辑。扩展方法可以聪明地 logit 来查看对象是否属于实际类型,然后在执行该方法之前将其强制转换回来。When you run this simple program it explains how overloading works :). The answer is that the underlying type's method will be called. And it should work the same way for
IQueryable
andIEnumerable
; that is, the original object's method will be called since even though we cast it something else the actual implementation is of the original type. But when there is an extension method the extension method for the object which is referenced is used, so in that case it depends on the logic in the extension method. The extension method could have come clever logit to see if the object is of an actual type and then cast it back before it executes the method.