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

发布于 2024-08-16 20:47:32 字数 864 浏览 9 评论 0原文

我在我们的应用程序中有一个奇怪的行为。我想迭代表 (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 语句来删除对扩展方法的任何引用。但这会产生令人讨厌的副作用,迫使我们完全限定任何类型声明。不漂亮。

预先感谢您的任何意见。

埃里克.

I have a strange behavior in our application. I want to iterate over the rows of a table (DataTable). I wanted to use the AsEnumerable() extension method from DataTableExtensions class. Sonmething like:

foreach(var thing in table.AsEnumerable())
{
...
}

When it compiles, it complains that I need to reference some ESRI DLLs (GIS application). After some digging, I found a few extension methods from a referenced DLL that extend some of the types from ESRI (e.g. IEnumField, IEnumLayer, etc.)

Obviously, a DataTable is nothing like what those are and I can't seem to find why it is trying to bind to AsEnumerable(this IEnumLayer) instead of AsEnumerable(this DataTable). The funny thing is also that we are using Resharper (awesome tool!) and Resharper is on our side: when you navigate to the definition, it takes you to AsEnumerable(this DataTable) in the object browser.

I can't post much code sample here without posting thousands of lines of proprietary code so I am just looking for a I had the same issue once and I fixed it with... type of answer.

The obvious solution was to remove any reference to the extension methods by removing all using statements for that namespace. But this has the nasty side effect of forcing us to fully qualify any type declaration. Not pretty.

Thanks in advance for any input.

Eric.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

悲念泪 2024-08-23 20:47:32

您可以使用 using [alias = ]class_or_namespace; 的 alias = 部分。然后你会得到类似 using my = System.Data; 的东西,然后将它与 my.DataTable.AsEnumerable(); 一起使用

You could use the alias = part of the using [alias = ]class_or_namespace;. Then you would have something like using my = System.Data; and then use it with my.DataTable.AsEnumerable();

画骨成沙 2024-08-23 20:47:32
foreach(var thing in ((DataTable)table).AsEnumerable())
{
...
}

尝试一下....

foreach(var thing in ((DataTable)table).AsEnumerable())
{
...
}

Try that....

唠甜嗑 2024-08-23 20:47:32

我不太确定为什么会遇到这个问题,但一种潜在的解决方法是放弃扩展方法语法糖,只处理 AsEnumerable 作为普通静态方法:

foreach (var thing in DataTableExtensions.AsEnumerable(table))
{
    // do something
}

I'm not really sure why you're hitting this problem, but one potential workaround would be to forgo the extension method syntactic sugar and just treat AsEnumerable as a normal static method:

foreach (var thing in DataTableExtensions.AsEnumerable(table))
{
    // do something
}
墟烟 2024-08-23 20:47:32

你能发布你的类层次结构吗?

以下代码显示选择了最派生的编译时类型扩展方法。
它适用于您的代码吗?

    [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));
    }
}

Can you post your class hierarchy?

The following code shows that the most derived compile-time type Extension Method is choosen.
Does it applies to your code?

    [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());
    }

Used this classes:

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));
    }
}
峩卟喜欢 2024-08-23 20:47:32

也许以下方法效果最好:

foreach (DataRow dr in table.Rows)
{
}

Perhaps the following would work best:

foreach (DataRow dr in table.Rows)
{
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文