Как работает разрешение перегрузки метода (LINQ Где метод расширения )?

Если у меня есть переменная типа IQueryable, у меня есть четыре метода расширения для Whereв пространстве имен Systm.Linq, доступных:

public static IQueryable Where(this IQueryable source,
    Expression> predicate);
public static IQueryable Where(this IQueryable source,
    Expression> predicate);
public static IEnumerable Where(this IEnumerable source,
    Func predicate);
public static IEnumerable Where(this IEnumerable source,
    Func predicate);

(Последние два, потому что IQueryableнаследуется от IEnumerable.)

Если я использую переменную типаObjectQuery(в пространстве именSystem.Data.Objects)У меня есть пять доступных перегрузок Where, а именно четыре выше (, потому что ObjectQueryреализует IQueryableи IEnumerableсреди других интерфейсов )и, кроме того, метод экземпляра этого класса:

public ObjectQuery Where(string predicate,
    params ObjectParameter[] parameters);

Если я делаю одну и ту же ошибку программирования при использовании IQueryableили ObjectQuery, я получаю очень разные ошибки компилятора. Вот пример программы (стандартный шаблон консольного приложения C #в сборке VS2010 SP1 + System.Data.Entity.dll, добавленный в ссылки на проект, ошибка компилятора находится в комментарии под четырьмя примерами):

using System.Data.Objects;
using System.Linq;

namespace OverloadTest
{
    public class Test
    {
        public int Id { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            IQueryable queryable = null;
            ObjectQuery objectQuery = null;

            var query1 = queryable.Where(t => t.Name == "XYZ");
            // no definition for "Name" in class OverloadTest.Test

            var query2 = queryable.Where(t => bla == blabla);
            // "bla", "blabla" do not exist in current context

            var query3 = objectQuery.Where(t => t.Name == "XYZ");
            // Delegate System.Func
            // does not take 1 argument

            var query4 = objectQuery.Where(t => bla == blabla);
            // Delegate System.Func 
            // does not take 1 argument
        }
    }
}

"Закорючки" в компиляторе тоже выглядят иначе:

enter image description here

Я понимаю первые две ошибки. Но почему компилятор явно хочет использовать перегрузку номер 4 (сFunc predicate)в последних двух примерах и не говорит мне, что «Имя» не определено в классе Testи что «бла» и «блабла» не существуют в текущем контексте?

Я ожидал, что компилятор сможет безопасно исключить перегрузку № 5 (Я не передаю stringв качестве параметра )и перегрузку № 2 и 4 (Я не передаю лямбда-выражение с два параметра(t,i) =>...)но мое ожидание не кажется правильным.

В качестве примечания :я столкнулся с этой проблемой, просматривая этот вопрос . Спрашивающий сказал там, что четвертый запрос в вопросе не компилируется (он имеет точно такую ​​же ошибку компилятора в примере № 3 и 4 выше ),но этот запрос как раз и есть решение его проблемы и мне кажется что-то (переменная или имя свойства? )написано неправильно в запросе (он не подтвердил это, хотя )но эта ошибка компилятора не дает полезного указания на то, что не так.

Изменить

Ссылаясь на очень полезный комментарий Мартина Харриса ниже:

В примере query4ошибка «Delegate System.Func не принимает 1 аргумент » — это ошибка, отображаемая в окне всплывающей подсказки при наведении указателя мыши на волнистую линию. В окне вывода компилятора на самом деле четыре ошибки в этом порядке:

  • Делегат System.Func не принимает 1 аргумент
  • «лямбда-выражение» не может быть преобразовано в «строку», поскольку «строка» не является типом делегата
  • Имя "бла" не существует в текущем контексте
  • Имя «blabla» не существует в текущем контексте

Но почему компилятор не жалуется на первую ошибку для первых двух примеров, использующих IQueryable?

7
задан Community 23 May 2017 в 12:01
поделиться