web-dev-qa-db-fra.com

Vérification du paramètre de type d'une méthode générique en C #

Est-il possible de faire quelque chose comme ça en C #:

public void DoSomething<T>(T t)  
{
    if (T is MyClass)
    {
        MyClass mc = (MyClass)t 
        ...
    }
    else if (T is List<MyClass>)
    {
        List<MyClass> lmc = (List<MyClass>)t
        ...
    }
}
53
synergetic

Oui:

if (typeof(T) == typeof(MyClass))
{
    MyClass mc = (MyClass)(object) t;
}
else if (typeof(T) == typeof(List<MyClass>))
{
    List<MyClass> lmc = (List<MyClass>)(object) t;
}

C'est un peu étrange que vous ayez besoin de passer par un transtypage en objet, mais c'est juste la façon dont les génériques fonctionnent - il n'y a pas autant de conversions d'un type générique que vous pourriez vous y attendre.

Bien sûr, une autre alternative consiste à utiliser la vérification du temps d'exécution normal:

MyClass mc = t as MyClass;
if (mc != null)
{
    // ...
}
else
{
    List<MyClass> lmc = t as List<MyClass>;
    if (lmc != null)
    {
        // ...
    }
}

Cela se comportera différemment du premier bloc de code si t est bien sûr nul.

Je voudrais essayer pour éviter ce type de code si possible, cependant - cela peut parfois être nécessaire, mais l'idée de méthodes génériques est de pouvoir écrire générique du code qui fonctionne de la même manière pour tout type.

92
Jon Skeet

Nous sommes en 2017 et nous avons maintenant C # 7 avec correspondance de motifs. Si votre type T hérite de object vous pouvez vous coder comme ceci

void Main()
{
    DoSomething(new MyClass { a = 5 });
    DoSomething(new List<MyClass> { new MyClass { a = 5 }, new MyClass { a = 5 }});
}


public void DoSomething(object t)
{
    switch (t)
    {
        case MyClass c:
            Console.WriteLine($"class.a = {c.a}");
            break;
        case List<MyClass> l:
            Console.WriteLine($"list.count = {l.Count}");
            break;
    }
}

class MyClass
{
    public int a { get; set;}
}
8
Sousuke

À partir de C # 7, vous pouvez le faire de manière concise avec l'opérateur is:

public void DoSomething<T>(T value)  
{
    if (value is MyClass mc)
    {
        ...
    }
    else if (value is List<MyClass> lmc)
    {
        ...
    }
}

Voir la documentation: https://docs.Microsoft.com/en-us/dotnet/csharp/language-reference/keywords/is#pattern-matching-with-is

5
mark.monteiro

Je crois qu'il y a quelque chose de mal dans votre conception. Vous voulez comparer les types dans une méthode déjà générique. Les génériques sont destinés à faire face à une situation de type variable. Je recommande de le faire de cette façon ..

//Generic Overload 1
public void DoSomething<T>(T t)
    where T : MyClass
{
    ...
}

//Generic Overload 2
public void DoSomething<T>(T t)
    where T : List<MyClass>
{
    ...
}
3