我想我已经遇到了扩展方法和LINQ的极端情况.
今天我宣布了一些扩展方法,使我的代码更具可读性.所以我创建了一个获取对象并执行直接转换的扩展方法:
public static class GeneralExtensions
{
public static T Cast<T>(this object o)
{
return (T)o;
}
}
Run Code Online (Sandbox Code Playgroud)
目的是能够通过以下方式调用我的直接铸件:
MyObject.CastTo<MyInterface>();
Run Code Online (Sandbox Code Playgroud)
碰巧在同一个命名空间中我有一个具有LINQ表达式的扩展方法
using System;
using System.Collections.Generic;
using System.Linq;
public static class EnumExtenstions
{
public static IEnumerable<string> UseLinq(this IEnumerable<object> collection)
{
return (from object value in collection select value.ToString() ).ToList();
}
}
Run Code Online (Sandbox Code Playgroud)
将第一个扩展方法添加到我的代码库会导致下一个错误
Error CS1936 Could not find an implementation of the query pattern for source type 'object'. 'Select' not found.
Run Code Online (Sandbox Code Playgroud)
将两种扩展方法放在不同的命名空间(而不是引用),或重命名Cast为不同的名称解决问题.
我想更多地了解为什么会发生这种情况.它与LINQ有些重叠吗?如果是这样,为什么我Cast优先考虑?
在.NET Fiddle(Link)中找到代码
Eri*_*ert 12
我想更多地了解为什么会发生这种情况.它与LINQ有些重叠吗?
是!
当您查询表单时
from Foo bar in blah select baz
Run Code Online (Sandbox Code Playgroud)
这被编译器重写为一系列方法调用:
blah.Cast<Foo>().Select(bar => baz)
Run Code Online (Sandbox Code Playgroud)
方法调用就像普通方法调用一样被解析.如果blah有一个成员Cast那么它被使用; 如果没有,则搜索扩展方法.
如果是这样,为什么我的演员有优先权?
解决扩展方法的规则有点棘手,但基本规则是"最接近包含类胜利".如果您的扩展方法位于全局命名空间中的类中,并且LINQ扩展方法位于System.Linq命名空间中的类中,那么您的扩展更接近.为了进入你的类,编译器必须从当前命名空间"向上"到全局命名空间.要进入System.Linq,编译器必须"向上"到全局命名空间,然后进入System.Linq以找到正确的类.
特别要注意的是,C#编译器不会"回溯".它没有说"好吧,当我尝试使用Select时,返回对象的Cast的版本给了我一个错误;是否有另一个版本的Cast可以使用?" C#编译器只是说最好的Cast版本会产生错误,因此它不应该试图找到更糟糕的Cast版本.在这种特殊情况下,这是您想要的行为,但在许多情况下,您最终会得到一个名为的意外方法.C#更喜欢给出错误,而不是试图猜测你真正想要的方法.
这是对实际规则的过度简化,当多个嵌套命名空间中存在多个"using"指令时,这些规则会变得复杂.如果您需要确切的规则,请参阅规范.
但最好不要首先去那里.除非您打算以其完整性复制LINQ功能,否则不要将自己的扩展方法命名为Cast,Select,Where等.
更新:我刚刚意识到我没有在这里解决一个可能更大的问题:你的强制转换方法可能无法做你想做的事情,无论它的命名与查询模式的方法冲突.
我注意到你的强制转换方法比仅使用强制转换操作符更糟糕:
Cast<int>(123)不必要地插入int; (int)123才不是.Cast<short>(123)失败但(short)123成功.没有从盒装int到short的转换.Animal到Shape. Cast<Shape>(new Tiger())失败但(Shape) new Tiger()成功.q是一个可空的int,恰好是null. Cast<string>(q)成功!但是(string)q在编译时会失败等等.你的演员方法与真正的演员操作员有一些重叠,但它绝不是它的替代品.如果您的目的是捕获转换操作符的语义,那么您需要使用dynamic它,它在运行时再次启动编译器并对运行时类型进行编译时分析.
| 归档时间: |
|
| 查看次数: |
415 次 |
| 最近记录: |