Подтвердить что ты не робот

Нарушение изменения разрешения перегрузки метода в С# 6 - объяснение?

Недавно мы перешли от VS2013 к VS2017 в нашу компанию. После обновления наша кодовая база больше не будет строить. Мы получили бы следующую ошибку:

Вызов неоднозначен между следующими методами или свойствами: 'IRepository <T> .Get(объект, params Expression < Func < T, object → [])' и 'IRepository <T> .Get(object, params строка []) '

Вот сам вызов:

this.mainRepository.Get(newEntity.Id);

... и определение интерфейса:

public interface IRepository<T> where T : class
{
    T Get(object id, params Expression<Func<T, object>>[] includeExprs);
    T Get(object id, params string[] includeExprs);
}

Мне было интересно, может ли кто-нибудь объяснить, почему это так. Я подозреваю, что новая улучшенная функция перегрузки метода С# 6.0, но, глядя на спецификацию языка, я не смог узнать точное правило, ответственное за проблему.

ИЗМЕНИТЬ

Я написал следующее сообщение в блоге об этой проблеме: http://codewithstyle.info/method-overload-resolution-in-c-6-0-an-interesting-bug-story

4b9b3361

Ответ 1

Я обнаружил то же самое при обновлении до Visual Studio 2015, так что это не ново с 2017 годом, но оно является новым с 2013 года.

Я сообщил об этом на github:

Код, который компилируется в VS2013, не работает с CS0121 в 2015 году; перегрузки с разными параметрами параметров # 4458:

Проблема в том, что код неоднозначен, а новый компилятор Roslyn более строг на этом, чем предыдущий компилятор.

Проблема была закрыта действием, чтобы изменить документацию вместо возврата к старому поведению, как часть проблемы Добавить информацию о # 4458 в "Разрешение перегрузки .md" # 4922.

В частности, AlekseyTs прокомментировал это:

В интересах будущего здоровья нашего кода разрешения перегрузки мы решили сохранить нарушение (и правильное) поведение. Если мы получим больше, чем этот единственный случай, мы можем захотеть переоценить.

Итак, у вас это есть. Новый компилятор более строг в этом и вам нужно изменить свой код.

Учитывая комментарий выше, AlekseyTs, вы можете подумать о том, чтобы сообщить об этом Microsoft в github в качестве дополнительного такого случая. Если эта проблема становится все более широко распространенной сейчас, когда 2017 год отсутствует, потому что многие люди/компании ждали с обновлением, поскольку в комментарии говорится, что они могут захотеть переоценить.

Кроме того, причина, по которой вы ничего не нашли в (более старой) документации, заключается в том, что это была "скрытая функция" старшего компилятора, как видно из изменения, внесенные в документацию:

Старый компилятор реализовал специальные правила для разрешения перегрузки (не в спецификации языка) при наличии неиспользуемых параметров param-массива, а Roslyn более строгая интерпретация спецификации (теперь исправлена) помешала некоторым программы от компиляции.

(мой акцент)


Когда мы исправили тот же тип проблемы в нашем коде, мы закончили с чем-то вроде этого (пример с использованием вашего кода):

public interface IRepository<T> where T : class
{
    T Get(object id, Expression<Func<T, object>>[] tieBreaker, params Expression<Func<T, object>>[] includeExprs);
    T Get(object id, string tieBreaker, params string[] includeExprs);
}

обратите внимание на добавление двух параметров tieBreaker

Затем мы просто включили явный параметр в коллекцию с остальными внутри. Если вам нужно вызвать метод без каких-либо дополнительных опций, вы должны добавить третью перегрузку, в которой не должно быть явно указано, какую перегрузку следует вызывать, чтобы ваш конечный интерфейс выглядел следующим образом:

public interface IRepository<T> where T : class
{
    T Get(object id);
    T Get(object id, Expression<Func<T, object>>[] tieBreaker, params Expression<Func<T, object>>[] includeExprs);
    T Get(object id, string tieBreaker, params string[] includeExprs);
}