views:

144

answers:

4

Hi,

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.

A: 

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

Yuriy Faktorovich
Yuriy, could you post a quick snippet that would show how to use "using" with extension methods. I wanted to maintain the table.AsEnumerable() syntax. I believe that you are suggesting to switch to AsEnumerable(table) which is not as clear in our context.Regards.
Eric Liprandi
A: 
foreach(var thing in ((DataTable)table).AsEnumerable())
{
...
}

Try that....

BFree
Thanks. Had tried that already but still picking the other AsEnumerable().
Eric Liprandi
A: 

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
}
LukeH
A: 

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