web-dev-qa-db-fra.com

C # retourne différents types?

J'ai quelque chose comme ça:

public [What Here?] GetAnything()
{
     Hello hello = new Hello();
     Computer computer = new Computer();
     Radio radio = new Radio();

     return radio; or return computer; or return hello //should be possible?!      
}

J'ai une méthode et cette méthode me renvoie parfois différents types de valeurs (classes).

Comment puis-je le faire quand même et bien sûr plus tard pour travailler avec les variables, b.e radio.Play (); et jusqu'à présent?

Dois-je utiliser des génériques? Comment?

45
eMi

S'il n'y a pas de type de base ou d'interface commun, alors public object GetAnything() {...} - mais il serait généralement préférable de disposer d'une sorte d'abstraction telle qu'une interface commune. Par exemple, si Hello, Computer et Radio sont tous implémentés IFoo, ils pourraient alors renvoyer un IFoo.

41
Marc Gravell

Voici comment vous pourriez le faire avec des génériques:

public T GetAnything<T>()
{
   T t = //Code to create instance

   return t;
}

Mais vous devez savoir quel type vous souhaitez retourner au moment de la conception. Et cela voudrait dire que vous pourriez simplement appeler une méthode différente pour chaque création ...

36
RQDQ

Si vous pouvez créer une classe abstraite pour toutes les possibilités, cela est fortement recommandé:

public Hardware GetAnything()
{
     Computer computer = new Computer();

     return computer;    
}

abstract Hardware {

}

class Computer : Hardware {

}

Ou une interface:

interface IHardware {

}

class Computer : IHardware {

}

Si cela peut être quelque chose, vous pouvez envisager d'utiliser "objet" comme type de retour, car chaque classe dérive d'un objet.

public object GetAnything()
{
     Hello hello = new Hello();

     return hello;    
}
14
Rick Kuipers

La réponse de Marc devrait être la bonne, mais dans .NET 4, vous ne pouviez pas utiliser le type dynamique.

Ceci ne devrait être utilisé que si vous n'avez aucun contrôle sur les classes que vous retournez et s'il n'y a pas d'ancêtres communs (généralement avec interop) et que si vous n'utilisez pas dynamique, c'est beaucoup plus pénible que d'utiliser (casting chaque objet dans chaque étape :)).

Quelques articles de blog essayant d'expliquer quand utiliser Dynamic: http://blogs.msdn.com/b/csharpfaq/archive/tags/dynamic/

public dynamic GetSomething()
{
     Hello hello = new Hello();
     Computer computer = new Computer();
     Radio radio = new Radio(); 
     return // anyobject

}
14
tbt

utilisez le mot clé dynamic comme type de retour.

 private dynamic getValuesD<T>()
    {
        if (typeof(T) == typeof(int))
        {
            return 0;
        }
        else if (typeof(T) == typeof(string))
        {
            return "";
        }
        else if (typeof(T) == typeof(double))
        {
            return 0;
        }
        else
        {
            return false;
        }
    }

        int res = getValuesD<int>();
        string res1 = getValuesD<string>();
        double res2 = getValuesD<double>();
        bool res3 = getValuesD<bool>();

cordialement,

Abhijit

12
Abhijit Ojha

Pour compléter la réponse de @RQDQ en utilisant des génériques, vous pouvez combiner cela avec Func<TResult> (ou une variante) et déléguez la responsabilité à l'appelant:

public T GetAnything<T>(Func<T> createInstanceOfT)
{
    //do whatever

    return createInstanceOfT();
}

Ensuite, vous pouvez faire quelque chose comme:

Computer comp = GetAnything(() => new Computer());
Radio rad = GetAnything(() => new Radio());
10
aw04

Vous pouvez avoir le type de retour comme étant une super-classe des trois classes (que vous définissez ou que vous utilisiez simplement object). Vous pouvez ensuite renvoyer n'importe lequel de ces objets, mais vous devrez le redéfinir au bon type pour obtenir le résultat. Comme:

public object GetAnything()
{
     Hello hello = new Hello();
     Computer computer = new Computer();
     Radio radio = new Radio();

     return radio; or return computer; or return hello //should be possible?!      
}

Ensuite:

Hello hello = (Hello)getAnything(); 
4
Tudor

Vous pouvez simplement renvoyer un objet car tous les types sont dérivés de cet objet.

public Object GetAnything()
{
     Hello hello = new Hello();
     Computer computer = new Computer();
     Radio radio = new Radio();

     return radio; or return computer; or return hello //should be possible?!      
}

Vous pouvez ensuite lancer le type correspondant:

Hello hello = (Hello)GetAnything();

Si vous ne connaissiez pas le type, vous pouvez utiliser le mot clé is.

Object obj = GetAnything();
if (obj is Hello) {
    // Do something
}

Cela étant dit, je serais réticent à écrire du code comme ça. Il serait bien mieux d'avoir une interface implémentée par chacune de vos classes.

public ISpeak GetAnything()
{
     Hello hello = new Hello();
     Computer computer = new Computer();
     Radio radio = new Radio();

     return radio; or return computer; or return hello //should be possible?!      
}

interface ISpeak 
{
   void Speak();
}

et que chacune de vos classes implémente l'interface:

public class Hello : ISpeak
{
    void Speak() {
        Console.WriteLine("Hello");
    }
}

Vous pourriez alors faire quelque chose comme:

GetAnything().Speak();
3
Joe Axon

La solution de Rick est la "meilleure" voie à suivre dans la plupart des cas. Parfois, lorsque ce n'est pas disponible, vous souhaitez utiliser un objet comme type de base. Et vous pourriez utiliser la méthode comme ceci:

public object GetAnything()
{
     Hello hello = new Hello();
     Computer computer = new Computer();
     Radio radio = new Radio();

     return hello; // or computer or radio   
}

Pour l'utiliser, vous voudrez utiliser l'opérateur as, comme ceci:

public void TestMethod()
{
    object anything = GetAnything();
    var hello = anything as Hello;
    var computer = anything as Computer;
    var radio = anything as Radio;

    if (hello != null)
    {
        // GetAnything() returned a hello
    }
    else if (computer != null)
    {
        // GetAnything() returned a computer
    }
    else if (radio != null)
    {
        // GetAnything() returned a radio
    }
    else
    {
        // GetAnything() returned... well anything :D
    }
}

Dans votre cas, vous voulez appeler une méthode play. Donc, cela semblerait plus approprié:

interface IPlayable
{
    void Play();
}

class Radio : IPlayable
{
    public void Play() { /* Play radio */ }
}

class Hello : IPlayable
{
    public void Play() { /* Say hello */ }
}

class Computer : IPlayable
{
    public void Play() { /* beep beep */ }
}

public IPlayable GetAnything()
{
     Hello hello = new Hello();
     Computer computer = new Computer();
     Radio radio = new Radio();

     return hello; // or computer or radio   
}
2
Aidiakapi

Vous avez quelques options en fonction de la raison pour laquelle vous souhaitez renvoyer différents types.

a) Vous pouvez simplement renvoyer un objet et l'appelant peut le convertir (éventuellement après vérification du type) selon ce qu'il souhaite. Cela signifie bien sûr que vous perdez beaucoup des avantages du typage statique.

b) Si les types retournés ont tous en commun une "exigence", vous pourrez peut-être utiliser génériques avec constriantes .

c) Créez une interface commune entre tous les types de retour possibles, puis renvoyez l'interface.

d) Basculez sur F # et utilisez filtrage par motif et discriminez les unions. (Désolé, un peu la langue en échec!)

2
mavnn

Laissez la méthode renvoyer un objet à partir d'une classe ou d'une interface de base commune.

public class TV:IMediaPlayer
{
   void Play(){};
}

public class Radio:IMediaPlayer
{
   void Play(){};
}

public interface IMediaPlayer
{
   void Play():
}

public class Test
{
  public void Main()
  {
     IMediaPlayer player = GetMediaPlayer();
     player.Play();
  }


  private IMediaPlayer GetMediaPlayer()
  {
     if(...)
        return new TV();
     else
        return new Radio();
  }
}
2
Glenn

Définir un type unique pour tous n'est pas toujours possible. Même si vous le pouvez, la mise en œuvre est rarement facile. Je préfère utiliser les paramètres out. Le seul inconvénient est que vous devez connaître tous les types de retour à un stade avancé:

public void GetAnything(out Hello h, out Computer c, out Radio r)
{
     /// I suggest to:
     h = null;
     c = null;
     r = null; 
     // first, 

     // Then do whatever you have to do:
     Hello hello = new Hello();
     Computer computer = new Computer();
     Radio radio = new Radio();
}

Le type de retour peut être un void ou autre chose, comme bool un int ou un enum prédéfini, ce qui peut vous aider à vérifier l'existence d'exceptions ou de cas différents. partout où la méthode est utilisée.

1
mm_

J'ai une idée pour retourner plusieurs types .......

public object GetAnything(object o)
{
     Hello hello = new Hello();
     Computer computer = new Computer();
     Radio radio = new Radio();
     if(o == Hello){return hello;}
     if(o == Computer {return computer;}
     if(o == Radio) {return radio;}
}
1
amit sharma

Vous pouvez utiliser une classe externe, définir les types de propriétés à votre guise, puis l’utiliser dans votre fonction.

public class MultipleOpjects
{
    private List<string> _ObjectOne;
    public List<string> ObjectOne {
        get { return _ObjectOne; }
        set { _ObjectOne = value; }
    }
    private List<object> _ObjectTwo;
    public List<object> ObjectTwo {
        get { return _ObjectTwo; }
        set { _ObjectTwo = value; }
    }
    private object _ObjectThree;
    public object ObjectThree {
        get { return _ObjectThree; }
        set { _ObjectThree = value; }
    }
}
public MultipleOpjects GetAnything()
{
    MultipleOpjects Vrble = new MultipleOpjects();
    Vrble.ObjectOne  = SomeThing1;
    Vrble.ObjectTwo = SomeThing2;
    Vrble.ObjectThree = SomeThing3;

    return Vrble;      
}
1