Метод расширения, который работает в IEnumerable <T>и IQueryable <T>? - PullRequest
6 голосов
/ 10 октября 2011

Мне нужен метод расширения, который работает как с моим списком, так и с IQueryable.Методы расширения, приведенные ниже, достигают этого, но затем, если я добавлю другой идентичный метод расширения, но для другого совершенно не связанного типа, я получу неоднозначные ошибки компиляции вызова.Это почему?Разве компилятор не достаточно умен, чтобы знать, какой метод расширения работает?Я имею в виду, только один из этих вызовов допустим, почему компилятор не может сказать?Большое спасибо!

class ClassA
{
  public bool IsActive{ get; set;}
}

class ClassB
{
  public bool IsActive { get; set;}
}


// then here are my extensions

public static T IsActive<T>(this T enumerableOrQueryable, bool isActive)
  where T : IEnumerable<ClassA>
{
  return (T)enumerableOrQueryable.Where(x => x.IsActive == isActive);
}

public static T IsActive<T>(this T enumerableOrQueryable, bool isActive)
  where T : IEnumerable<ClassB>
{
  return (T)enumerableOrQueryable.Where(x => x.IsActive == isActive);
}

Ответы [ 3 ]

8 голосов
/ 10 октября 2011

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

Компилятор точноследуя правилам спецификации C #.

Связанные записи в блоге:

РЕДАКТИРОВАТЬ: Обратите внимание, что использование «enumerableOrQueryable» всегда собирается преобразовать ваше лямбда-выражение в делегат, а не дерево выражений.Так что, если вы хотите, чтобы она выполняла логику по-другому для базы данных, вам все равно понадобилось бы изменение.

РЕДАКТИРОВАТЬ: Ваша идея также не будет работать, потому что вы не получитетот же тип результата в любом случае - если вы вызываете Where на List<string>, возвращаемое значение не a List<string>.

То, что вы можете Сделайте это, если вы можете ввести новый интерфейс, который будет реализован как ClassA, так и ClassB:

public static IQueryable<T> IsActive<T>(this IQueryable<T> source, bool isActive)
    where T : ICanBeActive
{
    // Lambda converted to an expression tree
    return source.Where(x => x.IsActive == isActive);
}

public static IEnumerable<T> IsActive<T>(this IEnumerable<T> source,
    bool isActive) where T : ICanBeActive
{
    // Lambda converted to a delegate
    return source.Where(x => x.IsActive == isActive);
}
1 голос
/ 10 октября 2011

Компилятор не может разрешить неоднозначность из общих ограничений. Для вашего случая, вы не можете просто сделать что-то подобное?

public static IEnumerable<ClassA> IsActive(this IEnumerable<ClassA> enumerableOrQueryable, bool isActive)
{
  return enumerableOrQueryable.Where(x => x.IsActive == isActive);
}
0 голосов
/ 10 октября 2011

Вы можете попробовать что-то вроде этого:

public interface IActivatable
{
    bool IsActive { get; set; }
}

public class ClassA : IActivatable
{
    public bool IsActive{ get; set;}
}

public class ClassB : IActivatable
{
    public bool IsActive { get; set;}
}

public static class Ext
{
    public static IEnumerable<T> IsActive<T>(this IEnumerable<T> collection, bool isActive) where T : IActivatable
    {
        return collection.Where(x => x.IsActive == isActive);
    }
}
...