151 votes

Méthode générique de plusieurs(OU) contrainte de type

La lecture de cela, j'ai appris qu'il était possible de permettre une méthode pour accepter les paramètres de plusieurs types qui en fait une méthode générique. Dans l'exemple, le code suivant est utilisé avec un type de contrainte pour assurer le "U" est une IEnumerable<T>.

public T DoSomething<U, T>(U arg) where U : IEnumerable<T>
{
    return arg.First();
}

J'ai trouvé un code qui permettait d'ajouter plusieurs type de contraintes, telles que:

public void test<T>(string a, T arg) where T: ParentClass, ChildClass 
{
    //do something
}

Toutefois, ce code semble appliquer qu' arg doit être à la fois un type d' ParentClass et ChildClass. Ce que je veux faire est de dire que arg pourrait être un type d' ParentClass ou ChildClass de la manière suivante:

public void test<T>(string a, T arg) where T: string OR Exception
{
//do something
}

Votre aide est très appréciée comme toujours!

73voto

Botz3000 Points 23640

Ce n'est pas possible. Vous pouvez, cependant, de définir les surcharges pour des types spécifiques:

public void test(string a, string arg);
public void test(string a, Exception arg);

Si ceux qui font partie d'une classe générique, ils auront la préférence sur la version générique de la méthode.

30voto

Christopher Pfohl Points 4179

Boltz réponse est correcte à 100%, voici une brève explication:

Lorsque vous écrivez une méthode générique (ou pas) et de déclarer les types de paramètres que la méthode prend de la définition d'un contrat:

Si vous me donnez un objet qui sait comment faire l'ensemble des choses que De Type T, sait comment faire je peux livrer, soit "a": une valeur de retour de la type, je déclare, ou "b": une sorte de comportement qui utilise ce type.

Si vous essayez et donnez-lui plus d'un type à un moment (par la présence d'une ou d') ou essayer de l'obtenir pour retourner une valeur qui pourrait être plus d'un type de contrat devient floue:

Si vous me donnez un objet qui sait comment sauter à la corde ou sait comment calculer pi les 15 chiffres que je vais retourner un objet qui peut aller à la pêche ou peut-être mélanger le béton.

Le problème est que quand vous arrivez dans la méthode, vous n'avez aucune idée de si ils vous avons donné un IJumpRope ou PiFactory. En outre, lorsque vous aller de l'avant et d'utiliser la méthode (en supposant que vous avez obtenu comme par magie de la compilation) vous ne savez pas vraiment si vous avez un Fisher ou AbstractConcreteMixer. Fondamentalement, cela rend la chose de façon plus confuse.

La solution à votre problème en est un de deux possiblités:

  1. Définir plus d'une méthode qui définit chaque transformation possible, le comportement, ou quoi que ce soit. C'est Boltz de réponse. Dans le monde de la programmation, ceci est considéré comme la Surcharge de la méthode.

  2. Définir une classe de base ou de l'interface, qui sait comment faire toutes les choses que vous avez besoin pour la méthode et ont une méthode de prendre juste ce type. Cela peut impliquer l'emballage jusqu'à un string et Exception dans une petite classe pour définir la façon dont vous prévoyez de les faire correspondre à la mise en œuvre, mais ensuite tout est super clair et facile à lire. J'ai pu venir, quatre ans à partir de maintenant et de lire votre code et comprendre facilement ce qui se passe.

Que vous choisissez dépend de la façon dont compliquée choix 1 et 2 et de quelle manière extensible, il doit l'être.

Donc, pour votre situation spécifique, je vais vous imaginez que vous êtes juste de sortir un message ou quelque chose de l'exception:

public interface IHasMessage
{
    string GetMessage();
}

public void test(string a, IHasMessage arg)
{
    //Use message
}

Maintenant, tous vous avez besoin sont des méthodes qui transforment un string et Exception pour un IHasMessage. Très facile.

10voto

daryal Points 8211

Si ChildClass signifie qu'il est dérivé de Myclass, vous pouvez tout simplement écrire le suivant pour accepter à la fois Myclass et ChildClass;

public void test<T>(string a, T arg) where T: ParentClass 
{
    //do something
}

A l'inverse, si vous souhaitez utiliser deux types différents avec aucun héritage relation entre eux, vous devez prendre en compte les types d'application de la même interface;

public interface ICommonInterface
{
    string SomeCommonProperty { get; set; }
}

public class AA : ICommonInterface
{
    public string SomeCommonProperty
    {
        get;set;
    }
}

public class BB : ICommonInterface
{
    public string SomeCommonProperty
    {
        get;
        set;
    }
}

ensuite, vous pouvez écrire votre description de fonction;

public void Test<T>(string a, T arg) where T : ICommonInterface
{
    //do something
}

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