4 votes

Erreur avec List<T>.Contains(T) dans une requête LINQ

Je me demande pourquoi ça ne marche pas. Merci de votre compréhension.

    static void Main(string[] args)
    {
        List<int> foo = new List<int> { 1, 2, 3 };
        var myResult = MyTest<int>(foo);
    }

    private static List<int> MyTest<T>(List<T> input)
    {
        List<int> bar = new List<int> { 2, 3, 4 };
        return bar.Where(b => input.Contains(b)).ToList();
    }

La sortie attendue de MyTest() est une liste { 2, 3 }. Cependant, le compilateur signale deux erreurs sur input.Contains(b) comme suit :

  1. Argument 1 : ne peut pas convertir de 'int' en 'T'.

  2. La meilleure méthode surchargée correspondant à 'System.Collections.Generic.List.Contains(T)' possède des arguments non valides.

Cette clause Where() fonctionne bien si je n'utilise pas de listes génériques.

Il s'agit d'une simplification de mon problème réel, alors s'il vous plaît ne restez pas bloqué sur "pourquoi écrivez-vous ceci ?". Le problème est l'erreur et pourquoi elle se produit.

Révisé pour (espérons-le) plus de clarté :

namespace SandBox
{

class Foo
{
    public int FooInt { get; set; }
    public string FooString { get; set; }
}

class Program
{
    private static List<Foo> fooList = new List<Foo> {
            new Foo() {FooInt = 1, FooString = "A"},
            new Foo() {FooInt = 2, FooString = "B"},
            new Foo() {FooInt = 3, FooString = "C"}
    };

    static void Main(string[] args)
    {
        List<int> myIntList = new List<int> { 1, 2 };
        var myFirstResult = GetFoos<int>(myIntList);

        List<string> myStringList = new List<string> { "A", "B" };
        var mySecondResult = GetFoos<string>(myStringList);
    }

    /// <summary>
    /// Return a list of Foo objects that match the input parameter list
    /// </summary>
    private static List<Foo> GetFoos<T>(List<T> input)
    {
        //***
        // Imagine lots of code here that I don't want to duplicate in 
        // an overload of GetFoos()
        //***

        if (input is List<int>)
        {
            //Use this statement if a list of integer values was passed in
            return fooList.Where(f => input.Contains(f.FooInt));
        }
        else if (input is List<string>)
        {
            //Use this statement if a list of string values was passed in
            return fooList.Where(f => input.Contains(f.FooString));
        }
        else
            return null;
    }
}
}

Les mêmes erreurs de compilation sont signalées sur input.Contains(f.Property) .

2voto

Sam I am Points 18913

input devrait être un List<int>

et ensuite, à chaque fois que vous appelez la fonction, si T n'est pas un int, vous saurez qu'il retournera toujours une liste vide de toute façon.

la fonction n'a pas beaucoup de sens lorsque T n'est pas un int.

2voto

user287107 Points 4383

Également une autre solution

static void MainT(string[] args)
{
    List<int> foo = new List<int> { 1, 2, 3 };
    var myResult = MyTest<int>(foo);
}

private static List<int> MyTest<T>(List<T> input) where T : IEquatable<int>
{
    List<int> bar = new List<int> { 2, 3, 4 };
    return bar.Where(b => input.Any(i => i.Equals(b))).ToList();
}

1voto

David B Points 53123

Il suffit de regarder cette fonction de manière isolée.

private static List<int> MyTest<T>(List<T> input)
{
    List<int> bar = new List<int> { 2, 3, 4 };
    return bar.Where(b => input.Contains(b)).ToList();
}

Et si T était un objet... ou une chaîne... rien n'empêche T d'être ces types. Si T était l'un de ces types, l'instruction input.Contains(b) n'aurait pas de sens.

Le compilateur se plaint parce que vous autorisez des types qui n'ont pas de sens avec les déclarations dans le corps de la méthode.

0voto

Ian Newson Points 2163

Essayez ça :

static void Main(string[] args)
{
    List<int> foo = new List<int> { 1, 2, 3 };
    var myResult = MyTest<int>(foo);
}

private static List<int> MyTest<T>(List<T> input)
{
    List<int> bar = new List<int> { 2, 3, 4 };
    return bar.Where(b => input.OfType<int>().Contains(b)).ToList();
}

Le problème est qu'au compilateur n'a aucune idée du type T. Puisque T peut être n'importe quoi, vous ne pouvez pas appeler une méthode qui attend un int ( input.Contains ).

0voto

Reacher Gilt Points 1299

Le compilateur ne peut pas garantir que tout <T> -- tout <T> , DateTime, objet, quoi que ce soit -- pourra être converti en un int. C'est pourquoi vous obtenez votre première erreur.

Dans certaines circonstances, vous pouvez spécifier un type d'objet dans la signature de votre fonction :

 private static List<int> MyTest<T>(List<T> input)  where T : someObject

Cela ne fonctionnera pas dans votre cas car int est un struct. Vous pouvez l'utiliser de bien d'autres façons (les autres réponses données présentent d'excellentes méthodes), mais vous devrez adapter votre stratégie actuelle d'une manière ou d'une autre.

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