web-dev-qa-db-fra.com

Résoudre les méthodes d'extension/l'ambiguïté LINQ

J'écris un complément pour ReSharper 4. Pour cela, je devais faire référence à plusieurs assemblys de ReSharper. L'un des assemblys (JetBrains.Platform.ReSharper.Util.dll) contient un espace de noms System.Linq, avec un sous-ensemble de méthodes d'extension déjà fournies par System.Core.

Lorsque je modifie le code, cela crée une ambiguïté entre ces extensions, de sorte que je ne peux pas utiliser OrderBy, par exemple. Comment pourrais-je résoudre ceci? Je voudrais utiliser le noyau LINQ , et non ceux de ReSharper.

J'obtiens l'erreur suivante en essayant de compiler:

L'appel est ambigu entre le méthodes ou propriétés suivantes: 'System.Linq.Enumerable.OrderBy<string,int>(System.Collections.Generic.IEnumerable<string>, System.Func<string,int>)' and 'System.Linq.Enumerable.OrderBy<string,int>(System.Collections.Generic.IEnumerable<string>, System.Func<string,int>)'

EDIT: J'ai essayé la suggestion ci-dessous, malheureusement sans succès. En attendant, j'ai "résolu" le problème en supprimant les références à System.Core. De cette façon, je pourrais utiliser les extensions fournies par les fichiers ReSharper DLL.

J'ai téléchargé un exemple de programme où je viens d'importer les fichiers ReSharper DLL dont j'avais besoin. J'ai changé l'alias de System.Core en SystemCore, ajouté la directive extern alias, mais cela ne fonctionnait toujours pas. Si j'ai manqué quelque chose, s'il vous plaît faites le moi savoir . P.S. Les références concernent les fichiers ReSharper v4.1 DLL installés dans le répertoire d'exécution par défaut dans "C:\Program Files\JetBrains\ReSharper\v4.1\...".

27
Igal Tabachnik

Ce n'est plus un problème, car je peux utiliser les extensions LINQ, telles que fournies par les fichiers ReSharper DLL, même en ciblant .NET 3.0.

M. Skeet avait encore raison! Je suis en mesure d'utiliser la syntaxe LINQ complète, tout en ciblant .NET 3.0 dans les propriétés du projet et en ne faisant pas référence à System.Core!

2
Igal Tabachnik

C’est probablement l’un des rares cas où il est judicieux d’utiliser un alias extern .

Dans la page de propriétés pour la référence à System.Core (c.-à-d. Sous Références, sélectionnez System.Core, cliquez avec le bouton droit de la souris et sélectionnez "Propriétés"), définissez la valeur "Aliases" sur "global, SystemCore" (ou simplement "SystemCore" si c'est vide pour commencer).

Puis dans votre code, écrivez:

extern alias SystemCore;
using SystemCore::System.Linq;

Cela rendra tous les types pertinents etc. de l'espace de noms System.Linq de System.Core.dll disponibles. Le nom "SystemCore" est ici arbitraire - vous pouvez l'appeler "DotNet" ou autre chose si cela rend les choses plus claires pour vous.

41
Jon Skeet

Ce n'est pas vraiment une réponse, mais cela peut permettre aux autres de reproduire le problème plus facilement (à partir de la ligne de commande - vous pouvez le faire avec deux projets dans Visual Studio si vous le souhaitez).

1) Créez BadLinq.cs et construisez-le en tant que BadLinq.dll:

using System.Collections.Generic;

namespace System.Linq
{
    public static class Enumerable
    {
        public static IEnumerable<T> Where<T>(this IEnumerable<T> source, 
                                              Func<T,bool> predicate)
        {
            return null;
        }
    }
}

2) Créer Test.cs:

extern alias SystemCore;

using System;
using SystemCore::System.Linq;

static class Test
{
    static void Main()
    {
        var names = new[] { "Larry", "Curly", "Moe" };

        var result = names.Where(x => x.Length > 1);
    }
}

3) Compilez Test.cs en spécifiant l’alias externe:

csc Test.cs /r:BadLinq.dll /r:SystemCore=System.Core.dll

Cela échoue avec:

Test.cs (11,28): erreur CS1061: 'System.Array' ne contient pas un définition pour 'Où' et no méthode d'extension 'Where' acceptant un premier argument de type 'System.Array' peut être trouvé (il vous manque une directive d'utilisation ou une référence d'assemblage?)

Si vous le modifiez pour ne pas utiliser une méthode d'extension (c.-à-d. Enumerable.Where), cela fonctionne correctement avec l'alias externe.

Je pense que ce peut être un bogue du compilateur. J'ai envoyé par courrier électronique une liste de diffusion privée que l'équipe C # a lue. Je mettrai à jour cette réponse ou en ajouterai une nouvelle à la nouvelle réponse.

6
Jon Skeet

Pour que ReSharper soit aussi compatible que possible avec les nombreuses solutions avec lesquelles il est utilisé, il est construit sur .NET 2.0. LINQ, etc. sont entrés dans C # 3.0, ils ne sont donc pas disponibles dans cette version du Framework. Donc, JetBrains a ajouté sa propre version.

La solution consiste à construire votre complément avec .NET 2.0 également.

2
Nick Chadwick

J'ai eu le problème de référence ambigu en utilisant System.ComponentModel. Visual Studio se plaignait de l'existence d'un fichier DLL dans les versions v2 et v4. J'ai pu résoudre le problème en supprimant la référence au fichier système DLL et en le lisant.

1
Ujain

J'ai trouvé ce même type d'ambiguïté lorsque PagedList est utilisé dans MVC (.Net 4.5, MVC 5). J'ai trouvé que si je prenais l'objet de l'argument qui était ambigu et le jetais explicitement en premier, le problème était résolu. Si l'ambiguïté était entre une méthode prenant System.Linq.Enumerable et une méthode prenant System.Collections.Generic.IEnumerable en tant que paramètre en question, et la source étant du type System.Collections.Generic.IEnumerable, je utilisez la méthode d'extension dessus. Je le lance. Dans cet exemple, ma méthode de référentiel renvoie une liste:

searchRequest.CaseSearchResults = csr.SelectMatchingCases(searchRequest);
var results = searchRequest.CaseSearchResults.AsEnumerable<CaseSearchResult>();
int pageNum = (int)(ViewBag.PageNum ?? 1);
var pageResults =results.ToPagedList<CaseSearchResult>(pageNum, 5);

L'appel de la méthode d'extension sur searchRequest.CaseSearchResults a provoqué l'erreur d'ambiguïté. explicitement casting en results puis en appelant l'extension qui a fonctionné.

0
Joey Morgan

J'ai eu une situation similaire. Après deux heures de lutte, j'ai réalisé que mes bibliothèques comportaient des noms d'espaces de noms en double. Si vous utilisez le fichier Dynamic.cs publié par Microsoft, la seule chose à faire est de renommer l’espace de nom actuel en un nom différent, ce qui sera résolu.

//Copyright (C) Microsoft Corporation.  All rights reserved.

using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;

namespace System.Linq.Dynamic    <- for example to Linq.Dynamic
{
0
Ryan

J'ai eu le même problème, même avec un alias externe, et j'ai soulevé comme un bogue du compilateur sur Connect. Pour le moment, la solution consiste à renoncer à la syntaxe de la méthode d'extension.

Le bogue est corrigé pour Visual Studio 2010.

0
Ben Challenor

C'est vraiment une erreur du compilateur.

J'ai eu le même problème et je l'ai résolu en nettoyant et en reconstruisant le projet. Après cela, le problème a disparu.

0
DOHXEHAPO

Une solution serait de déplacer tout votre code vers une classe partielle qui utilise le code ReSharper. Dans celui-ci, vous importeriez uniquement l'espace de noms ReSharper et pas System.Core.

Dans le reste de la classe partielle, vous importeriez tous les autres espaces de noms nécessaires, y compris System.Core, mais pas l'espace de noms ReSharper.

0
Fabrice