自定义扩展方法与框架扩展方法发生冲突。为啥?
Posted
技术标签:
【中文标题】自定义扩展方法与框架扩展方法发生冲突。为啥?【英文标题】:custom extension methods collide with framework extension methods. Why?自定义扩展方法与框架扩展方法发生冲突。为什么? 【发布时间】:2010-12-30 22:21:55 【问题描述】:我在我们的应用程序中有一个奇怪的行为。我想遍历表的行 (DataTable
)。我想使用来自DataTableExtensions
类的AsEnumerable()
扩展方法。类似的东西:
foreach(var thing in table.AsEnumerable())
...
编译时,它抱怨我需要引用一些 ESRI DLL(GIS 应用程序)。经过一番挖掘,我从引用的 DLL 中找到了一些扩展方法,这些方法扩展了 ESRI 中的某些类型(例如IEnumField
、IEnumLayer
等)
显然,DataTable
与它们完全不同,我似乎无法找到为什么它试图绑定到 AsEnumerable(this IEnumLayer)
而不是 AsEnumerable(this DataTable)
。有趣的是,我们正在使用 Resharper(很棒的工具!),而 Resharper 就在我们身边:当您导航到定义时,它会将您带到对象浏览器中的 AsEnumerable(this DataTable)
。
如果不发布数千行专有代码,我无法在此处发布太多代码示例,所以我只是在寻找一个我曾经遇到过同样的问题,然后我用...... 类型修复了它回答。
显而易见的解决方案是通过删除该命名空间的所有 using 语句来删除对扩展方法的任何引用。但这有一个令人讨厌的副作用,即迫使我们完全限定任何类型声明。不漂亮。
提前感谢您的任何意见。
埃里克。
【问题讨论】:
我相信您可以尝试编写一个简短但完整的示例,just 显示了该问题。毕竟,您所要做的就是创建一个DataTable
并调用AsEnumerable
。如果您可以从编译器发布 exact 错误消息,那将有很大帮助。
【参考方案1】:
也许以下方法效果最好:
foreach (DataRow dr in table.Rows)
【讨论】:
【参考方案2】:你能发布你的类层次结构吗?
以下代码显示选择了最派生的编译时类型扩展方法。 它适用于您的代码吗?
[TestMethod]
public void Test1()
IEnumerable<MyCustomClass> myCustomList = new MyCustomList()
new MyCustomClass() Int1 = 1,
new MyCustomClass() Int1 = 2,
new MyCustomClass() Int1 = 3,
;
//Ignores MyCustomList method and uses IEnumerable<> method.
Assert.AreEqual(2, myCustomList.Where(x => x.Int1 > 1).Count());
[TestMethod]
public void Test2()
MyCustomList myCustomList = new MyCustomList()
new MyCustomClass() Int1 = 1,
new MyCustomClass() Int1 = 2,
new MyCustomClass() Int1 = 3,
;
//Uses MyCustomList method
Assert.AreEqual(1, myCustomList.Where(x => x.Int1 > 1).Count());
[TestMethod]
public void Test3()
ISomeInterface myCustomList = new MyCustomList()
new MyCustomClass() Int1 = 1,
new MyCustomClass() Int1 = 2,
new MyCustomClass() Int1 = 3,
;
//If your type is ISomeInterface, the compiler uses ISomeInterface method, even if the runtime instance is MyCustomList
Assert.AreEqual(0, myCustomList.Where(x => x.Int1 > 1).Count());
[TestMethod]
public void Test4()
MyDerivedCustomList myCustomList = new MyDerivedCustomList()
new MyCustomClass() Int1 = 1,
new MyCustomClass() Int1 = 2,
new MyCustomClass() Int1 = 3,
;
//Even if MyDerivedCustomList implements ISomeInterface, the compiler uses MyCustomList method
Assert.AreEqual(1, myCustomList.Where(x => x.Int1 > 1).Count());
[TestMethod]
public void Test5()
ISomeInterface myCustomList = new MyDerivedCustomList()
new MyCustomClass() Int1 = 1,
new MyCustomClass() Int1 = 2,
new MyCustomClass() Int1 = 3,
;
//If your type is ISomeInterface, the compiler uses ISomeInterface method, even if the runtime instance is MyDerivedCustomList
Assert.AreEqual(0, myCustomList.Where(x => x.Int1 > 1).Count());
使用过这个类:
public class MyCustomClass
public int Int1 get; set;
public class MyCustomList : List<MyCustomClass>, ISomeInterface
public MyCustomList() : base()
public MyCustomList(IEnumerable<MyCustomClass> coll) : base(coll)
public interface ISomeInterface : IEnumerable<MyCustomClass>
public class MyDerivedCustomList : MyCustomList, ISomeInterface
public MyDerivedCustomList() : base()
public MyDerivedCustomList(IEnumerable<MyCustomClass> coll) : base(coll)
public static class MyExtensions
/// <summary>
/// Where(x => x.Int1 > 2)
/// </summary>
public static IEnumerable<MyCustomClass> Where(this MyCustomList myList, Func<MyCustomClass, bool> predicate)
return new MyCustomList(Enumerable.Where(myList, predicate).Where(x => x.Int1 > 2));
/// <summary>
/// Where(x => x.Int1 > 3)
/// </summary>
public static IEnumerable<MyCustomClass> Where(this ISomeInterface myList, Func<MyCustomClass, bool> predicate)
return new MyCustomList(Enumerable.Where(myList, predicate).Where(x => x.Int1 > 3));
【讨论】:
【参考方案3】:我不太确定您为什么会遇到这个问题,但一种可能的解决方法是放弃扩展方法语法糖,将 AsEnumerable
视为普通静态方法:
foreach (var thing in DataTableExtensions.AsEnumerable(table))
// do something
【讨论】:
【参考方案4】:foreach(var thing in ((DataTable)table).AsEnumerable())
...
试试看....
【讨论】:
【参考方案5】:您可以使用 using [alias = ]class_or_namespace;
的别名 = 部分。然后你会得到类似using my = System.Data;
的东西,然后将它与my.DataTable.AsEnumerable();
一起使用
【讨论】:
Yuriy,你能否发布一个快速的 sn-p 来展示如何将“使用”与扩展方法一起使用。我想维护 table.AsEnumerable() 语法。我相信您建议切换到 AsEnumerable(table) ,这在我们的上下文中并不那么清楚。问候。以上是关于自定义扩展方法与框架扩展方法发生冲突。为啥?的主要内容,如果未能解决你的问题,请参考以下文章
MCS-51单片机扩展系统中,片外程序存储器和片外数据存储器共处同一个地址空间,为啥不会发生总线冲突?