2012-05-08 18 views
7

Voglio dare un parametro a un metodo e voglio che il mio metodo restituisca i dati osservando il parametro. I dati possono essere in tipo di booleano, stringa, int o così via. Come posso restituire un tipo di variabile da un metodo? Non voglio restituire un tipo di oggetto e quindi trasmetterlo a un altro tipo. Per esempio:Tipo di ritorno variabile di un metodo in C#

BlaBla VariableReturnExampleMethod(int a) 
{ 
    if (a == 1) 
     return "Demo"; 
    else if (a == 2) 
     return 2; 
    else if (a == 3) 
     return True; 
    else 
     return null; 
} 

La ragione per cui voglio che è che ho un metodo che legge una colonna selezionata di una riga dal database. I tipi di colonne non sono gli stessi, ma devo restituire le informazioni di ogni colonna.

+2

su un lato nota, invece di tutte queste cose, se qualcun'altro dico fare una piccola ricerca in un interruttore http://msdn.microsoft.com/en-us/library/06tc147t(v=vs.80). aspx – RhysW

+0

@RhysW +1 per lo switch, ma anche in questo caso 'else' non è richiesto,' if' sarà sufficiente. –

+0

sei sicuro se devi restituire solo alcuni tipi standard come int, string ecc? o sono più classi dal codice ur? – nawfal

risposta

13

Come posso restituire un tipo di variabile da un metodo? Non voglio restituire un tipo di oggetto e quindi trasmetterlo a un altro tipo.

Beh questo è fondamentalmente ciò che si fare hanno a che fare. In alternativa, se si sta utilizzando C# 4 si potrebbe fare il tipo di ritorno dynamic, che consente la conversione di essere implicita:

dynamic VariableReturnExampleMethod(int a) 
{ 
    // Body as per question 
} 

... 

// Fine... 
int x = VariableReturnExampleMethod(2); 

// This will throw an exception at execution time 
int y = VariableReturnExampleMethod(1); 

Fondamentalmente, di specificare i tipi di lasciare che il compilatore sa cosa aspettarsi. Come può funzionare se il tipo è noto solo al tempo di esecuzione ? Il motivo per cui la versione dynamic funziona è che in pratica dice al compilatore di posticipare il suo normale lavoro fino al tempo di esecuzione - così si perde la normale sicurezza che lascerebbe fallire il secondo esempio in fase di compilazione.

+0

Non so, sto aspettando i vostri consigli. – sanchop22

+0

@petre: È difficile dare altri consigli senza sapere perché volevi farlo in primo luogo. –

+1

Mi piace come la risposta di Jon Skeet abbia avuto tre +1 in 1 minuto di risposta, anche prima che fosse elaborata. Deve essere bello :) – Tim

4

Usa dynamic Voce nel luogo di BlahBlah se si prendono di mira .Net 4.0 ma se uno minore, allora object è la soluzione più sicura, perché è la classe base per tutte le altre classi si può pensare.

0

Utilizzare il tipo di reso come object, quindi è possibile ottenere qualsiasi tipo di reso. devi gestire l'etere di ritorno attraverso la riflessione o altro metodo.

controllo questo:

void Main() 
{ 
    object aa = VariableReturnExampleMethod(3); 
    Console.WriteLine(aa.ToString()); 
} 

object VariableReturnExampleMethod(int a) 
{ 
    if (a == 1) 
     return "Demo"; 
    else if (a == 2) 
     return 2; 
    else if (a == 3) 
     return true; 
    else 
     return null; 
} 

Edit: Io sono in favore di oggetti fortemente tipizzati e si può implementare facilmente su piattaforma .net.

if(returnedValue !=null) 
{ 

string currentDataType = returnedValue.GetType().Name; 
object valueObj = GetValueByValidating(currentDataType, stringValue); 
} 


public object GetValueByValidating(string strCurrentDatatype, object valueObj) 
     { 
      if (valueObj != "") 
      { 
       if (strCurrentDatatype.ToLower().Contains("int")) 
       { 
        valueObj = Convert.ToInt32(valueObj); 
       } 
       else if (strCurrentDatatype.ToLower().Contains("decimal")) 
       { 
        valueObj = Convert.ToDecimal(valueObj); 
       } 
       else if (strCurrentDatatype.ToLower().Contains("double") || strCurrentDatatype.ToLower().Contains("real")) 
       { 
        valueObj = Convert.ToDouble(valueObj); 
       } 
       else if (strCurrentDatatype.ToLower().Contains("string")) 
       { 
        valueObj = Convert.ToString(valueObj); 
       } 
       else 
       { 
        valueObj = valueObj.ToString(); 
       } 
      } 
      else 
      { 
       valueObj = null; 
      } 
      return valueObj; 
     } 
+0

Ha chiesto esplicitamente una soluzione che non ha lanciato – Crisfole

2

suona come questo potrebbe essere un buon caso per generics. Se sai quale tipo di dati ti aspetti quando lo chiami, puoi chiamare quella particolare versione generica della funzione.

+0

Anche se i generici possono aiutare in altre situazioni, ha vinto Aiuta nella situazione fornita dall'OP * a meno che * il chiamante sappia che il tipo verrà restituito dall'argomento fornito al momento della compilazione ... improbabile. –

+0

@Adam Houldsworth - Sulla base della sua descrizione del problema (il fatto che si trattasse di una chiamata che restituiva valori da un database) sembrava che il codice chiamante potesse effettivamente sapere cosa si aspettava. Sembra che forse ha una funzione ReadFromDatabase (nomecampo), e in questo caso probabilmente conoscerai il tipo di dati del campo. Non è un buon design, a mio parere, ma i generici renderebbero più facile. – Tim

+0

Consideriamo 'Field ' da DataTable come esempio di questo. Le uniche buone opzioni sono questo o solo il ritorno dell'oggetto, e come OP ha escluso l'altra opzione, questo è ciò che rimane. – Servy

2

Considerare l'utilizzo di qualcosa come Dapper-dot-net (scritto da Marc Gravell e Sam Saffron nel nostro Stack Overflow proprio personale) per estrarre le cose dal DB. Gestisce il database per la mappatura degli oggetti per te.

Inoltre, se non si desidera utilizzare uno strumento e si sta eseguendo il pull da un database e si conoscono i tipi di dati delle varie colonne in fase di compilazione (come sembra, si dovrebbe) lavorare fila per fila piuttosto che colonna per colonna.

//Pseudo-code: 
List<DatabaseObject> objects = new List<DatabaseObject>(); 
foreach(var row in DatabaseRows) 
{ 
    var toAdd = new DatabaseObject(); 
    toAdd.StringTypeVariable = "Demo"; 
    toAdd.IntTypeVariable = 2; 
    toAdd.BoolTypeVariable = true; 
    object.Add(toAdd); 
} 

Nota: è possibile utilizzare la sintassi inizializzatore di oggetto, e LINQ qui, ma questo è il modo più semplice che potrei pensare a provare le canzoni di questo senza usare un sacco di roba in più.

Si noti inoltre, che qui sto supponendo che non realtà desidera tornare "Demo", 2, e vero, ma i valori che utilizzano la riga. Significa solo che cambierai i valori codificati su: row.GetStringType(stringColumnIdx) o qualcosa di simile.

+0

+1 per la raccomandazione per riga per riga anziché colonna per colonna – Bob2Chiv

0

Guardo le tue richieste e uno è meglio del secondo, ma l'ultimo devo riscrivere per capire meglio la soluzione. E questa soluzione saltava molto se l'altro stack e la sostituiva foreach su Tipi enum, dove possiamo implementare tutti i tipi di cui abbiamo bisogno. Mi piace più usare la dinamica, ma anche questa è utilizzabile.

principale funzione GetValueByValidating valore restituito se è di tipo definito e possibile, in altri casi return false sguardo Niranjan-Kala questa è la tua funzione principale dopo la riscrittura.



      /// 
     /// Enum of wanted types 
     /// 
     public enum Types 
     { 
      [ExtendetFlags("int")] 
      INT, 
      [ExtendetFlags("decimal")] 
      DECIMAL, 
      [ExtendetFlags("double")] 
      DOUBLE, 
      [ExtendetFlags("real")] 
      REAL, 
      [ExtendetFlags("string")] 
      STRING, 
      [ExtendetFlags("object")] 
      OBJECT, 
      [ExtendetFlags("null")] 
      NULLABLE 
     } 
     /// 
     /// Cycle by types when in enum exist string reference on type (helper) 
     /// 
     /// 
     /// 
     public static Types GetCurrentType(string container) 
     { 
      foreach (Types t in Enum.GetValues(typeof(Types))) 
      { 
       if (container.Contains(t.GetFlagValue())) 
       { 
        return t; 
       } 
      } 
      return Types.NULLABLE; 
     } 
     /// 
     /// Return object converted to type 
     /// 
     /// 
     /// 
     /// 
     public static object GetValueByValidating(string strCurrentDatatype, object valueObj) 
     { 
      var _value = valueObj != null ? valueObj : null; 
      try 
      { 
       Types _current = _value != null ? GetCurrentType(strCurrentDatatype.ToLower()) : Types.NULLABLE; 

       switch (_current) 
       { 
        case Types.INT: 
         valueObj = Convert.ToInt32(valueObj); 
         break; 
        case Types.DECIMAL: 
         valueObj = Convert.ToDecimal(valueObj); 
         break; 
        case Types.DOUBLE: 
         valueObj = Convert.ToDouble(valueObj); 
         break; 
        case Types.REAL: 
         valueObj = Convert.ToDouble(valueObj); 
         break; 
        case Types.STRING: 
         valueObj = Convert.ToString(valueObj); 
         break; 
        case Types.OBJECT: 
         break; 
        case Types.NULLABLE: 
         throw new InvalidCastException("Type not handled before selecting, function crashed by retype var."); 
       } 
      } catch (InvalidCastException ex) 
      { 
       Log.WriteException(ex); 
       valueObj = false; 
      } 

      return valueObj; 
     } 


+0

Ecco il codice promesso di ExtendetFlags di Enum: [ExtendetFlags Class] (http://stackoverflow.com/a/36173834/4689104) –

Problemi correlati