2010-12-04 6 views
0

J'ai une méthode qui permet de convertir un nombre de chaîne à la T, par exemple intC# Un problème avec retour T

public static T GetItemIdFromUrl<T>(string itemName) 
{ 
    try 
    { 
     ... 
     int ad_id = int.Parse(stringNumber); 

     return (T)(object)ad_id; 
    } 
    catch 
    { 
     return (T)(object)-1; 
    } 
} 

mais en conséquence j'avoir un code hexadécimal 0xffffffa5 au lieu de 91. Pourquoi ?

+0

Qu'est-ce que c'est censé faire exactement? Pourquoi essayez-vous de convertir un entier en 'T'? –

+1

Pourquoi la méthode est-elle générique? Il échouera toujours si T n'est pas int ... –

+0

non, je coupe le nombre de la chaîne (le paramètre) et ensuite je le lance comme un T (int, décimal, tout ce dont j'ai besoin) – Tony

Répondre

3

Même si votre intention est de généraliser la gestion de différents types numériques (par exemple, double, decimal, etc.), ce n'est pas la manière de le faire. Lorsque vous boîte-object, puis Unbox-T, it will only work if the boxed type actually is T. En d'autres termes, il va pas effectuer une conversion de type pour vous.

La seule façon (que je sache) pour faire la conversion du type de object à ce que vous voulez est en utilisant la classe Convert:

return (T)Convert.ChangeType(ad_id, typeof(T)); 

Même cela est fragile, évidemment (comme il ne sera pas fonctionne si T est un type non numérique); mais au moins, il n'y aura pas d'exceptions dans presque tous les cas que vous essayez de couvrir. (Votre méthode telle qu'elle est actuellement mise en œuvre jetteront pour chaque T sauf int.)

5

Eh bien, il est difficile de savoir avec certitude pourquoi il est de retour 0xffffffa5 sans connaître la chaîne d'entrée, mais votre code va lancer une exception si T est autre chose que ce soit int ou un ENUM avec un type de base sous-jacente de int. Par exemple, lancera si T est double. Votre méthode n'est pas vraiment générique - la valeur est en essayant pour retourner est toujours un int. Pourquoi votre méthode n'est pas simplement déclarée pour renvoyer int? Si vous voulez convertir de int à un autre type (double, long, peu importe), laissez simplement cette conversion se faire lors de l'affectation. La conversion unboxing dans votre code ne fonctionnera pas à moins que T soit int ou une énumération appropriée (ce dernier semble improbable). Une chose à noter est que 0xffffffa5 est le modèle binaire de -91. Est-il possible que vous avez seulement vu ce résultat dans le débogueur, et le résultat est censé être -91 plutôt que 91?

+0

dans le paramètre peut être par exemple la chaîne 'myString-123'. Dans de nombreux autres endroits, ce nombre sera utilisé comme int, décimal, etc – Tony

+1

@Tony: Votre code va encore échouer. Écoutez ce que tout le monde dit: cette méthode est brisée. Complètement cassé. Le rendre générique est * ne pas vous aider *. –

0

Je pense que vous faites quelque chose d'autre où vous montrer les points de suspension (...):

try 
    { 
     ... 
     int ad_id = int.Parse(stringNumber); 

     return (T)(object)ad_id; 
    } 

parce que j'essayé votre échantillon et je reçois un retour int.

Vous n'avez vraiment aucun moyen, actuellement, de faire en sorte que votre retour se fasse au travail. Votre méthode s'appuiera sur des informations très spécifiques. Fournissez un peu plus d'informations là où vous avez les ellipses et une meilleure solution peut être recommandée. Comme Jon mentionne, un intendant nullable? serait mieux. Testez la condition et si ce n'est pas un bon retour, vous pouvez vérifier myInt.HasValue.

Je suis méditais une solution complète à ce problème et est venu avec les éléments suivants:

static List<Type> numerics = new List<Type>(); 

static void Main(string[] args) 
{ 
    numerics.Add(typeof(Decimal)); 
    numerics.Add(typeof(Double)); 
    numerics.Add(typeof(Int16)); 
    numerics.Add(typeof(Int32)); 
    numerics.Add(typeof(Int64)); 
    numerics.Add(typeof(Single)); 
    numerics.Add(typeof(UInt16)); 
    numerics.Add(typeof(UInt32)); 
    numerics.Add(typeof(UInt64)); 

    Console.WriteLine("StringNumber 55: {0} {1}", typeof(int), GetItemIdFromUrl<int>("55")); 
    Console.WriteLine("StringNumber 5B99: {0} {1}", typeof(int), GetItemIdFromUrl<int>("5B99")); 

    Console.ReadKey(); 
} 

public static T GetItemIdFromUrl<T>(string stringNumber) 
{ 
    try 
    { 
     if (numerics.Contains(typeof(T))) 
      return (T)Convert.ChangeType(stringNumber, typeof(T)); 
     else 
      return default(T); 
    } 
    catch (ArgumentException argEx) 
    { 
     Console.WriteLine("Exception\r\n{0}", argEx); 
     return default(T); 
    } 
    catch (FormatException formatEx) 
    { 
     Console.WriteLine("Exception\r\n{0}", formatEx); 
     return default(T); 
    } 
} 

Du 2 WriteLine vous serez en mesure de voir ce qui se passe si un passe numérique non valide. Bien sûr, j'ai inclus les messages Exception juste pour que vous puissiez voir ce qu'ils reviendraient. Ce n'est peut-être pas une solution glamour, mais je pense que c'est viable.

Je suis également venu avec ceci:

public static class GetNumeric<T> 
{ 
    public static Func<string, T> Value = stringValue => (T)Convert.ChangeType(stringValue, typeof(T)); 
} 

Bien que je voudrais encore envelopper l'appel dans un bloc try/catch.

+0

Je n'ai pas mentionné 'int?' Du tout. J'ai utilisé 'int' à la fin d'une question, mais je n'avais pas l'intention de parler de types nullables du tout. –

+0

@Jon: ma faute ... quand j'ai vu votre message il y a un point d'interrogation et je l'ai vu comme int? ... Je vais réviser ... – IAbstract

1

Je pense que vous avez une incompréhension fondamentale de ce que sont les génériques et comment ils sont censés être utilisés. Tout le point des génériques est d'avoir l'avantage de travailler sur différents types tout en ne perdant pas la sécurité de type ce qui se passe quand vous lancez object

Ceci dit Jon Skeet a probablement raison de dire que c'est probablement la façon dont le débogueur affiche le résultat.