2012-01-24 14 views
37

Ho qualcosa di simile:C# restituisce diversi tipi?

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?!  
} 

Ho un metodo e questo metodo mi restituisce a volte diversi tipi di valori (classi).

Come posso farlo comunque e naturalmente in seguito per lavorare con le variabili, b.e radio.Play(); e così lontano?

Devo usare i farmaci generici? Come?

+1

Vedi http://stackoverflow.com/questions/1048884/c-overriding-return-types per un problema simile e una soluzione. Devo essere onesto, però, in quanto penso che tu abbia un problema di progettazione se lo stai facendo; se hai dei tipi definiti allora dovrebbe essere possibile strutturare il tuo codice senza questo. – dash

+0

è possibile restituire 'object' e quindi trasmettere il risultato oppure utilizzare un metodo generico – balexandre

+1

Qual è il problema effettivo che si sta tentando di risolvere? Il tipo di ritorno – RQDQ

risposta

36

Se non esiste un tipo di base o un'interfaccia comune, quindi public object GetAnything() {...} - ma di solito sarebbe preferibile avere una sorta di astrazione come un'interfaccia comune. Ad esempio se Hello, Computer e Radio sono tutti implementati IFoo, quindi è possibile restituire uno IFoo.

+0

ok grazie! – eMi

3

È possibile impostare il tipo di ritorno come una superclasse delle tre classi (definite dall'utente o utilizzate semplicemente object). Quindi è possibile restituire uno qualsiasi di questi oggetti, ma sarà necessario eseguire il cast di nuovo al tipo corretto quando si ottiene il risultato. Come:

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?!  
} 

Poi:

Hello hello = (Hello)getAnything(); 
+0

ok grazie! – eMi

+0

Funziona molto bene, a patto che non è necessario fare alcun riferimento a un "oggetto" memorizzato all'interno di quel metodo. Ad esempio, provare a restituire un oggetto già esistente senza crearne uno nuovo potrebbe essere una sfida. – ooXei1sh

10

Se si può fare una classe astratta per tutte le possibilità poi che è altamente raccomandato:

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

    return computer;  
} 

abstract Hardware { 

} 

class Computer : Hardware { 

} 

o un'interfaccia:

interface IHardware { 

} 

class Computer : IHardware { 

} 

Se può essere qualsiasi cosa il n puoi considerare di usare "oggetto" come tipo di ritorno, perché ogni classe deriva dall'oggetto.

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

    return hello;  
} 
29

Ecco come si potrebbe fare con i generici:

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

    return t; 
} 

ma dovreste sapere che tipo si voleva tornato in fase di progettazione. E ciò significherebbe che puoi semplicemente chiamare un metodo diverso per ogni creazione ...

-2

Potrebbe essere necessario il tipo "dinamico"?

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

    return /*what boject you needed*/ ;`enter code here` 
} 
+0

Questo è ** non ** per quale dinamica è un uso corretto per. Dynamic è solo un involucro di fantasia attorno al riflesso e viene utilizzato per oggetti veramente dinamici. Non per semplici scenari orientati agli oggetti. – Aidiakapi

10

La risposta di Marc dovrebbe essere quella corretta, ma in .NET 4 non si poteva andare anche con il tipo dinamico.

Questo dovrebbe essere usato solo se non si ha il controllo sulle classi che si ritornano e non ci sono antenati comuni (di solito con interop) e solo se non si usa la dinamica è molto più doloroso che usare (gettare ogni oggetto in ogni passaggio :)).

Pochi post sul blog cercando di spiegare quando usare dinamica: 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 

} 
+0

In realtà, puoi fare bene senza la parola chiave dinamica. Proprio come gli altri miei commenti. Questo non è uno scenario in cui si utilizza la dinamica. – Aidiakapi

+0

@Aidiakapi So che potreste farlo senza dinamica, ecco perché ho aggiunto la seconda riga della mia risposta. Quale è un buon uso della dinamica, penso.Per esempio potresti avere un problema simile usando la dinamica dell'interop di Office puoi risparmiare molte sequenze di tasti :) – tburi

+0

La dinamica ha i suoi usi, ma la maggior parte della gente la vede come una parola chiave magica e la usa eccessivamente . (Come in questo esempio.) Dovrebbe essere evitato ovunque possibile. – Aidiakapi

1

avete alcune opzioni a seconda del motivo si desidera restituire tipi diversi.

a) È possibile restituire un oggetto e il chiamante può eseguire il cast (eventualmente dopo i controlli di tipo) su ciò che desidera. Ciò significa ovviamente che si perdono molti vantaggi della digitazione statica.

b) Se i tipi restituiti hanno tutti un "requisito" in comune, è possibile utilizzare generics with constriants.

c) Creare un'interfaccia comune tra tutti i tipi di restituzione possibili e quindi restituire l'interfaccia.

d) Passare a F # e utilizzare pattern matching e unioni discriminate. (Mi dispiace, un po 'di lingua sotto controllo lì!)

+0

Lol, oppure potresti andare in C++ e usare 'void *'>. <, Dubito che voglia usare un linguaggio di programmazione diverso da quello che ha chiesto. – Aidiakapi

+0

Ecco perché è l'opzione d. Detto questo, ho diversi progetti che hanno una base di codice F #/C# mista; ognuna delle lingue ha i suoi punti di forza. – mavnn

+0

Sono d'accordo, proprio come fa C++/CLI, che può anche essere condiviso nei progetti. Tuttavia penso che sia abbastanza estraneo alla domanda. (Non fraintendermi, mi piace F #, è ottimo per casi molto specifici.) – Aidiakapi

1

Lascia che il metodo restituisca un oggetto da una comune base o interfaccia.

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

Si potrebbe semplicemente restituire un oggetto poiché tutti i tipi discendono da Object.

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?!  
} 

Si potrebbe quindi lanciare al suo tipo rilevanti:

Hello hello = (Hello)GetAnything(); 

Se non sapevano cosa del tipo sarebbe stata allora si potrebbe utilizzare la parola chiave is.

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

Detto questo, sarei riluttante a scrivere un codice del genere. Sarebbe molto meglio avere un'interfaccia che è implementata da ciascuna delle tue classi.

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(); 
} 

e hanno ciascuna delle classi implementare l'interfaccia:

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

È quindi possibile fare qualcosa di simile:

GetAnything().Speak(); 
1

soluzione di Rick è il modo 'migliore' per andare in più casi. A volte, quando non è disponibile, si desidera utilizzare l'oggetto come tipo di base. E si potrebbe utilizzare il metodo come questo:

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

    return hello; // or computer or radio 
} 

Per usarlo, si vuole utilizzare l'operatore as, in questo modo:

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 
    } 
} 

Nel tuo caso si desidera chiamare un metodo play. Quindi questo sembra più appropriato:

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 
} 
0

È possibile utilizzare la classe esterna, impostare i tipi di proprietà come desiderato, quindi utilizzarli nella funzione.

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;  
} 
5

costruire sulla risposta da @RQDQ utilizzando farmaci generici, è possibile combinare questo con Func<TResult> (o qualche variazione) e delegare la responsabilità al chiamante:

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

    return createInstanceOfT(); 
} 

allora si può fare qualcosa di simile:

Computer comp = GetAnything(() => new Computer()); 
Radio rad = GetAnything(() => new Radio()); 
0

ho un'idea per la restituzione di più tipi .......

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;} 
} 
+0

Questo non fornisce una risposta alla domanda. Una volta che hai [reputazione] sufficiente (http://stackoverflow.com/help/whats-reputation) sarai in grado di [commentare qualsiasi post] (http://stackoverflow.com/help/privileges/comment); invece [fornisci risposte che non richiedono chiarimenti da parte del richiedente] (http://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can- i-do-, invece). - [Dalla recensione] (/ recensione/post di bassa qualità/12733494) – Johan

+2

Ehi la mia risposta ha funzionato per me uomo .... È necessario convalidare la funzione chiamante avendo qualcosa di simile a questo var a = GetAnything (oggetto o) if (a.GetType() == typeof (Computer) {} else if (a.GetType() == typeof (Hello) {} else if (a.GetType() == typeof (Radio) {} –

0

Definire un singolo tipo per tutti non è sempre possibile. Anche se quando è possibile, l'implementazione è raramente facile. Preferisco usare i parametri out. L'unica avvertenza è che è necessario conoscere tutti i tipi restituiti in avanzato:

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(); 
} 

Il tipo di ritorno può essere una void, o qualcos'altro, come bool un int o un predefinito enum che può aiutare a controllare per le eccezioni o diversi casi in cui viene utilizzato il metodo.

0

utilizzare la parola chiave dynamic come tipo restituito.

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>(); 

saluti,

Abhijit