Cum pot face ca tipul de returnare al unei metode să fie generic? (Programare, C#,.Net, Generice, Tip De Retur)

MacGyver a intrebat.

Există o modalitate de a face această metodă generică, astfel încât să pot returna un șir de caractere, bool, int sau double? În momentul de față, returnează un șir de caractere, dar dacă este capabil să găsească „true” sau „false” ca valoare de configurare, aș dori să returneze un bool, de exemplu.

    public static string ConfigSetting(string settingName)
    {  
         return ConfigurationManager.AppSettings[settingName];
    }

Comentarii

  • Există o modalitate de a ști ce tip este fiecare configurație? –  > Por thecoshman.
  • Cred că întrebarea pe care doriți să o puneți cu adevărat este „Cum pot face ca configurația aplicației mele să fie puternic tipizată?”. A trecut prea mult timp de când am lucrat cu asta pentru a scrie un răspuns adecvat, totuși. –  > Por Simon.
  • Da, în mod ideal, nu vreau să fie nevoie să trec tipul în metodă. Voi avea doar cele 4 tipuri pe care le-am menționat. Deci, dacă este setat „true”/”false”, vreau ca această funcție să returneze un boolean (fără a fi nevoie să îl trec în metodă), probabil că pot combina int și double în doar double, iar restul ar trebui să fie un șir de caractere. Ceea ce se răspunde deja va funcționa bine, dar trebuie să trec tipul de fiecare dată, ceea ce probabil este bine. –  > Por MacGyver.
  • Comentariul dvs. sună ca și cum ați cere o metodă care să returneze un bool cu tip puternic (sau un șir de caractere, sau int, sau ce vreți) în timpul execuției pe baza datelor reale recuperate pentru cheia de nume a setării. C# nu va face acest lucru pentru dvs.; nu aveți cum să știți tipul acelei valori la compilare. Cu alte cuvinte, aceasta este o tipizare dinamică, nu statică. C# poate face acest lucru în locul dumneavoastră dacă folosiți opțiunea dynamic cuvântul cheie. Există un cost de performanță pentru acest lucru, dar pentru citirea unui fișier de configurare, costul de performanță este aproape sigur nesemnificativ. –  > Por phoog.
7 răspunsuri
Jon Skeet

Trebuie să o faci o metodă generică, așa cum ar fi aceasta:

public static T ConfigSetting<T>(string settingName)
{  
    return /* code to convert the setting to T... */
}

Dar apelant va trebui să specifice tipul pe care îl așteaptă. În acest caz, ați putea utiliza Convert.ChangeType, , presupunând că toate tipurile relevante sunt acceptate:

public static T ConfigSetting<T>(string settingName)
{  
    object value = ConfigurationManager.AppSettings[settingName];
    return (T) Convert.ChangeType(value, typeof(T));
}

Nu sunt pe deplin convins că toate astea sunt o idee bună, dar…

Comentarii

    23

  • /* cod pentru a converti setarea în T… */ și aici urmează întregul roman 🙂 –  > Por Adrian Iftode.
  • Nu ar fi nevoie ca acest lucru să cunoști tipul de setare pe care dorești să-l obții, ceea ce s-ar putea să nu fie posibil. –  > Por thecoshman.
  • @thecoshman: Ar fi, dar dacă nu ai ști, atunci ce faci cu valoarea returnată? –  > Por George Duckett.
  • În timp ce acest răspuns este, desigur, corect și, după cum observați, satisface cererea OP-ului, probabil că merită menționat faptul că vechea abordare a metodelor separate (ConfigSettingString, , ConfigSettingBool, , etc.) are avantajul unor corpuri de metode care vor fi mai scurte, mai clare și mai bine focalizate. –  > Por phoog.
  • Dacă acest lucru nu este recomandat, atunci care este scopul tipurilor de returnare generice? –  > Por bobbyalex.
BrokenGlass

Ați putea folosi Convert.ChangeType():

public static T ConfigSetting<T>(string settingName)
{
    return (T)Convert.ChangeType(ConfigurationManager.AppSettings[settingName], typeof(T));
}

RollerCosta

Există mai multe modalități de a face acest lucru(enumerate în funcție de prioritate, specifice problemei lui OP)

  1. Opțiunea 1: Abordare directă – Creați mai multe funcții pentru fiecare tip pe care îl așteptați, în loc să aveți o singură funcție generică.

    public static bool ConfigSettingInt(string settingName)
    {  
         return Convert.ToBoolean(ConfigurationManager.AppSettings[settingName]);
    }
    
  2. Opțiunea 2: Când nu doriți să folosiți metode sofisticate de conversie – Transformați valoarea în obiect și apoi în tip generic.

    public static T ConfigSetting<T>(string settingName)
    {  
         return (T)(object)ConfigurationManager.AppSettings[settingName];
    }
    

    Notă. Acest lucru va genera o eroare dacă castul nu este valid (cazul dvs.). Nu v-aș recomanda să faceți acest lucru dacă nu sunteți sigur de tipul de turnare, ci mai degrabă să alegeți opțiunea 3.

  3. Opțiunea 3: Generică cu siguranță de tip – Creați o funcție generică pentru a gestiona conversia de tip.

    public static T ConvertValue<T,U>(U value) where U : IConvertible
    {
        return (T)Convert.ChangeType(value, typeof(T));
    } 
    

    Notă. T este tipul așteptat, observați constrângerea where (tipul lui U trebuie să fie IConvertible pentru a ne salva de erori).

Comentarii

  • De ce să facem cea de-a treia opțiune generică în U? Nu are rost să o facem și face metoda mai greu de apelat. Acceptați pur și simplu IConvertible în schimb. Nu cred că merită să includem a doua opțiune pentru această întrebare, având în vedere că nu răspunde la întrebarea pusă. De asemenea, ar trebui probabil să redenumiți metoda din prima opțiune… –  > Por Jon Skeet.
Vinay Chanumolu

Trebuie să convertiți tipul valorii de returnare a metodei în tipul Generic pe care îl transmiteți metodei în timpul apelării.

    public static T values<T>()
    {
        Random random = new Random();
        int number = random.Next(1, 4);
        return (T)Convert.ChangeType(number, typeof(T));
    }

Trebuie să treceți un tip care este casabil pentru valoarea pe care o returnați prin metoda respectivă.

Dacă doriți să returnați o valoare care nu poate fi casată la tipul generic pe care îl treceți, ar trebui să modificați codul sau să vă asigurați că treceți un tip care poate fi casat pentru valoarea de returnare a metodei. Prin urmare, această abordare nu este recomandată.

Comentarii

  • Exact – pentru mine, ultima linie return (T)Convert.ChangeType(number, typeof(T)); a fost exact ceea ce îmi lipsea – noroc –  > Por Greg Trevellick.
Prabhakar

Creați o funcție și transmiteți parametrul put ca fiind de tip generic.

 public static T some_function<T>(T out_put_object /*declare as Output object*/)
    {
        return out_put_object;
    }

Comentarii

  • Acest lucru este de fapt destul de inteligent pentru câteva cazuri de utilizare. Cum ar fi extragerea datelor dintr-o bază de date. Știți că veți obține o listă de date de tip T. Doar că metoda de încărcare nu știe ce tip de T doriți chiar ACUM. Așa că trebuie doar să treceți o nouă listă „WantedObject” la această metodă, iar metoda își poate face treaba și umple lista înainte de a o returna. Frumos! –  > Por Marco Heumann.
Sid

Vă rugăm să încercați codul de mai jos:

public T? GetParsedOrDefaultValue<T>(string valueToParse) where T : struct, IComparable
{
 if(string.EmptyOrNull(valueToParse))return null;
  try
  {
     // return parsed value
     return (T) Convert.ChangeType(valueToParse, typeof(T));
  }
  catch(Exception)
  {
   //default as null value
   return null;
  }
 return null;
}

Adam Howard
 private static T[] prepareArray<T>(T[] arrayToCopy, T value)
    {
        Array.Copy(arrayToCopy, 1, arrayToCopy, 0, arrayToCopy.Length - 1);
        arrayToCopy[arrayToCopy.Length - 1] = value;
        return (T[])arrayToCopy;
    }

Efectuam acest lucru în tot codul meu și am vrut o modalitate de a-l pune într-o metodă. Am vrut să împărtășesc acest lucru aici pentru că nu a trebuit să folosesc Convert.ChangeType pentru valoarea de returnare. Este posibil să nu fie o practică optimă, dar a funcționat pentru mine. Această metodă primește o matrice de tip generic și o valoare care trebuie adăugată la sfârșitul matricei. Matricea este apoi copiată cu prima valoare eliminată, iar valoarea introdusă în metodă este adăugată la sfârșitul matricei. Ultimul lucru pe care îl returnez este matricea generică.