пользовательские методы расширения сталкиваются с методами расширения фреймворка. Почему?

У меня странное поведение в нашем приложении. Я хочу перебрать строки таблицы (DataTable). Я хотел использовать метод расширения AsEnumerable() из класса DataTableExtensions. Что-то вроде:

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

Когда он компилируется, он жалуется, что мне нужно сослаться на некоторые ESRI DLL (приложение ГИС). Немного покопавшись, я нашел несколько методов расширения из указанной DLL, которые расширяют некоторые типы из ESRI (например, IEnumField, IEnumLayer и т. д.).

Очевидно, что DataTable не похож на них, и я не могу понять, почему он пытается привязаться к AsEnumerable(this IEnumLayer) вместо AsEnumerable(this DataTable). Забавно также то, что мы используем Resharper (отличный инструмент!), и Resharper на нашей стороне: когда вы переходите к определению, вы переходите к AsEnumerable(this DataTable) в обозревателе объектов.

Я не могу опубликовать здесь много примеров кода, не опубликовав тысячи строк проприетарного кода, поэтому я просто ищу у меня была такая же проблема однажды, и я исправил ее с помощью... типа ответа.

Очевидным решением было удалить любую ссылку на методы расширения, удалив все операторы использования для этого пространства имен. Но у этого есть неприятный побочный эффект, вынуждающий нас полностью квалифицировать любое объявление типа. Не красиво.

Спасибо заранее за любые данные.

Эрик.


person Eric Liprandi    schedule 29.12.2009    source источник
comment
Я уверен, что вы могли бы попытаться написать короткий, но полный пример, который просто показывал эту проблему. В конце концов, все, что вам нужно сделать, это создать DataTable и вызвать AsEnumerable. Если бы вы могли опубликовать точное сообщение об ошибке от компилятора, это очень помогло бы.   -  person Jon Skeet    schedule 30.12.2009


Ответы (5)


Вы можете использовать псевдоним = часть using [alias = ]class_or_namespace;. Тогда у вас будет что-то вроде using my = System.Data;, а затем вы будете использовать его с my.DataTable.AsEnumerable();.

person Yuriy Faktorovich    schedule 29.12.2009
comment
Юрий, не могли бы вы опубликовать быстрый фрагмент, который показал бы, как использовать использование с методами расширения. Я хотел сохранить синтаксис table.AsEnumerable(). Я полагаю, что вы предлагаете переключиться на AsEnumerable(table), что не так ясно в нашем контексте. С Уважением. - person Eric Liprandi; 30.12.2009

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

Попробуй это....

person BFree    schedule 29.12.2009

Я не совсем уверен, почему вы столкнулись с этой проблемой, но одним из возможных обходных путей может быть отказ от синтаксического сахара метода расширения и просто обработка AsEnumerable как обычный статический метод:

foreach (var thing in DataTableExtensions.AsEnumerable(table))
{
    // do something
}
person LukeH    schedule 30.12.2009

Можете ли вы опубликовать свою иерархию классов?

В следующем коде показано, что выбран наиболее производный метод расширения типа времени компиляции. Это применимо к вашему коду?

    [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));
    }
}
person AntonioR    schedule 27.10.2010

Возможно, лучше всего подойдет следующее:

foreach (DataRow dr in table.Rows)
{
}
person BSick7    schedule 22.01.2011