32 votes

Changement radical dans la résolution de surcharge de la méthode en C # 6 - explication?

Nous avons récemment déménagé de VS2013 à VS2017 dans notre société. Après la mise à jour de notre base de code n'auraient plus à construire. Nous aimerions obtenir l'erreur suivante:

L'appel est ambigu entre les méthodes suivantes ou propriétés: 'IRepository<T>.Get(object, params Expression<Func<T, objet>> []) " et " IRepository<T>.Get(object, params string[])'

Voici l'appel lui-même:

this.mainRepository.Get(newEntity.Id);

...et la définition de l'interface:

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

Je me demandais si quelqu'un ici pourrait expliquer pourquoi c'est le cas. Je soupçonne la nouvelle Amélioration de la méthode de résolution de surcharge fonction de C# 6.0 mais en regardant le langage de spécification, je n'étais pas en mesure de trouver exactement la règle de responsable de la question.

MODIFIER

J'ai écrit un suivi post de blog à propos de ce problème: http://codewithstyle.info/method-overload-resolution-in-c-6-0-an-interesting-bug-story

39voto

Lasse V. Karlsen Points 148037

J'ai découvert la même chose lors de la mise à niveau de Visual Studio 2015, donc ce n'est pas nouveau à 2017, mais il est nouveau depuis 2013.

Je l'ai signalé sur github ici:

Code qui compile en VS2013 échoue avec CS0121 en 2015; les surcharges avec différents paramètres des types de paramètres #4458:

Le problème est que le code est ambiguë et le nouveau compilateur Roslyn est plus stricte que la précédente compilateur.

La question a été fermé avec une action pour changer la documentation plutôt que de revenir à l'ancien comportement, dans le cadre de l'émission d'Ajouter des informations à propos de #4458 de "Résolution de Surcharge.md" #4922.

En particulier, AlekseyTs a commenté ceci:

Dans l'intérêt de la santé future de notre résolution de surcharge de code, nous avons décidé de garder la rupture (et corriger) le comportement. Si nous obtenons plus de ce cas unique, nous voulons réévaluer.

Donc là vous l'avez. Le nouveau compilateur est plus stricte sur ce sujet et vous avez besoin de changer votre code.

Étant donné le commentaire ci-dessus par AlekseyTs, vous pourriez envisager de reporting pour Microsoft sur github comme un supplément de tels cas. Si ce genre de problème est de plus en plus répandue maintenant que 2017 est, parce que beaucoup de personnes/sociétés qui ont attendu la mise à jour, comme le commentaire dire ils veulent peut-être à réévaluer.

En outre, la raison pour laquelle vous ne trouverez pas n'importe quoi dans la (les plus anciens) de la documentation à ce sujet est que ce fut une "fonctionnalité cachée" de l'ancien compilateur, comme en témoigne le changement qu'ils ont fait pour la documentation:

L'ancien compilateur mise en œuvre des règles spéciales pour la résolution de surcharge (pas dans la spécification du langage) , en présence de la partie inutilisée des param-tableau des paramètres, et Roslyn l'interprétation plus stricte du cahier des charges (maintenant corrigé) a empêché certains programmes à partir de la compilation.

(mon emphase)


Lorsque nous avons fixé le même type de problème dans notre code, nous nous sommes retrouvés avec quelque chose comme ceci (exemple à l'aide de votre code):

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

avis de l'ajout des deux tieBreaker paramètres

Alors que nous venons de inclus le paramètre explicite dans la collection avec les autres à l'intérieur. Si vous avez besoin d'être en mesure d'appeler la méthode avec aucun de ces paramètres supplémentaires, vous devez ajouter un 3ème surcharge qui n'a pas à être explicite sur ce qui surcharge doit être appelé de la sorte, votre interface finale pourrait ressembler à ceci:

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X