自定义扩展方法与框架扩展方法发生冲突。为啥?

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 中的某些类型(例如IEnumFieldIEnumLayer 等)

显然,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单片机扩展系统中,片外程序存储器和片外数据存储器共处同一个地址空间,为啥不会发生总线冲突?

当扩展与打字稿中的react-final-form FieldRenderProps接口时发生冲突

CI框架扩展自定义控制器的方法

Jquery自定义扩展方法

为啥找不到我的自定义 WCF 行为扩展元素类型?

Dubbo3高级特性「框架与服务」自定义Dubbo服务容器及扩展容器实现分析