2010-04-29 11 views
5

Im essayant de faire un analyseur universel en utilisant des paramètres de type générique, mais je ne peux pas saisir le concept 100%paramètres de type générique utilisant des

private bool TryParse<T>(XElement element, string attributeName, out T value) where T : struct 
    { 
     if (element.Attribute(attributeName) != null && !string.IsNullOrEmpty(element.Attribute(attributeName).Value)) 
     { 
      string valueString = element.Attribute(attributeName).Value; 
      if (typeof(T) == typeof(int)) 
      { 
       int valueInt; 
       if (int.TryParse(valueString, out valueInt)) 
       { 
        value = valueInt; 
        return true; 
       } 
      } 
      else if (typeof(T) == typeof(bool)) 
      { 
       bool valueBool; 
       if (bool.TryParse(valueString, out valueBool)) 
       { 
        value = valueBool; 
        return true; 
       } 
      } 
      else 
      { 
       value = valueString; 
       return true; 
      } 
     } 

     return false; 
    } 

Comme vous pouvez le deviner, le code ne compile pas, depuis Je ne peux pas convertir int | bool | string en T (par exemple, value = valueInt). Merci pour vos commentaires, il pourrait même ne pas être possible de le faire. Utilisation de .NET 3.5

+0

Wow, bonne question. Ce soir, quand j'aurai le temps d'y revenir, je vais remettre en question toutes les réponses crédibles. –

Répondre

2

Voyant que vous n'écrire un grand if/then combo, je pense que vous seriez mieux simplement avec un tas de surcharge:

public static class Parser 
{ 
    private static string TryParseCommon(XElement element, string attributeName) 
    { 
     if (element.Attribute(attributeName) != null && !string.IsNullOrEmpty(element.Attribute(attributeName).Value)) 
     { 
      return element.Attribute(attributeName).Value; 
     } 

     return null; 
    } 

    public static bool TryParse(XElement element, string attributeName, out string value) 
    { 
     value = TryParseCommon(element, attributeName); 
     return true; 
    } 

    public static bool TryParse(XElement element, string attributeName, out int value) 
    { 
     return int.TryParse(TryParseCommon(element, attributeName), out value); 
    } 

    public static bool TryParse(XElement element, string attributeName, out bool value) 
    { 
     return bool.TryParse(TryParseCommon(element, attributeName), out value); 
    } 
} 
+0

oui c'est la façon facile ;-) –

1

J'ai effectué des méthodes d'analyse avant d'utiliser un TypeConverter.

TypeConverter converter = TypeDescriptor.GetConverter(typeof(T)); 
try 
{ 
    return (T)converter.ConvertFrom(value); 
} 
+0

cloué! Merci beaucoup! –

+0

bien que non avec des ints et des bool .. –

1

Cela pourrait fonctionner pour vous.

private bool TryParse<T>(XElement element, string attributeName,out T value) 
{ 
    if (element.Attribute(attributeName) != null && !string.IsNullOrEmpty(element.Attribute(attributeName).Value)) 
    { 
     string valueString = element.Attribute(attributeName).Value; 
     TypeConverter converter = TypeDescriptor.GetConverter(typeof(T)); 
     try 
     { 
      value = (T)converter.ConvertFrom(valueString); 
      return true; 
     } 
     catch 
     { 
      value = default(T); 
      return false; 
     } 
    } 
    value = default(T); 
    return false; 
} 
+3

int et bool sont des types struct! – flq

+0

a dû enlever la partie struct pour le faire fonctionner (à cause de la chaîne je suppose) –

2

pas la plus belle des choses, mais vous pouvez lancer votre T à quelque chose d'autre si vous faites le cycle sur l'objet, à savoir d'abord coulé à l'objet puis à T, ou vice versa. Je ne dis rien sur la boxe/unboxing, mais le compilateur l'acceptera.

1

Le problème est que vous essayez de faire quelque chose générique qui ne l'est pas vraiment. Même si vous parcourez manuellement chaque type que vous pouvez analyser vous-même, cela ne va pas permettre tous les types.

Pourquoi ne l'essayez-vous pas à la place? Tout d'abord définir un délégué qui décrit une méthode TryParse générale:

public delegate bool TryParser<T>(string text, out T value); 

restructurer ensuite votre méthode pour prendre un d'entre eux comme un paramètre:

// uglified code to fit within horizontal scroll area 
public bool TryParse<T> 
(XElement element, string attributeName, TryParser<T> tryParser, out T value) 
{ 
    value = default(T); 

    if (
     element.Attribute(attributeName) != null && 
     !string.IsNullOrEmpty(element.Attribute(attributeName).Value) 
    ) 
    { 
     string valueString = element.Attribute(attributeName).Value; 
     return tryParser(valueString, out value); 
    } 

    return false; 
} 

Maintenant, la surcharge ce pour tous les types standard est assez trivial :

public bool TryParseInt(XElement element, string attributeName, out int value) 
{ 
    return TryParse<int>(element, attributeName, int.TryParse, out value); 
} 

public bool TryParseBool(XElement element, string attributeName, out bool value) 
{ 
    return TryParse<bool>(element, attributeName, bool.TryParse, out value); 
} 

Et ainsi de suite. Ce qui est bien avec cette approche est qu'elle ne vous limite même pas à l'utilisation d'une contrainte where T : struct, ou même aux types .NET intégrés.

Un utilisateur de cette classe d'analyse peut analyser ses propres types personnalisés à partir d'un document XML simplement en définissant une méthode semblable à TryParse pour ses types personnalisés.

4

Les classes XElement et XAttribute fournissent toutes deux a set of explicit conversion operators (conversions) pour convertir facilement leur contenu en types primitifs .NET.

Par exemple, vous pouvez simplement faire:

XElement elem = // ... 

string value1 = (string)elem.Attribute("myString"); 
int value2 = (int)elem.Attribute("myInt"); 
int? value3 = (int?)elem.Attribute("myOptionalInt"); 
bool value4 = (bool)elem.Attribute("myBool"); 
+0

Wow, bon à savoir. –

+0

prise brillante. –

1

Cette méthode que je l'ai utilisé dans le passé peut aider un peu trop

public static T ChangeTypeTo<T>(this object value) 
{ 
    if (value == null) 
     return null; 

    Type underlyingType = typeof (T); 
    if (underlyingType == null) 
     throw new ArgumentNullException("value"); 

    if (underlyingType.IsGenericType && underlyingType.GetGenericTypeDefinition() 
              .Equals(typeof (Nullable<>))) 
    { 
     var converter = new NullableConverter(underlyingType); 
     underlyingType = converter.UnderlyingType; 
    } 

    // Guid convert 
    if (underlyingType == typeof (Guid)) 
    { 
     return new Guid(value.ToString()); 
    } 

    // Check for straight conversion or value.ToString conversion 
    var objType = value.GetType(); 

    // If this is false, lets hope value.ToString can convert otherwise exception 
    bool objTypeAssignable2typeT = underlyingType.IsAssignableFrom(objType); 

    // Do conversion 
    return (T) (objTypeAssignable2typeT ? 
       Convert.ChangeType(value, underlyingType) 
      : Convert.ChangeType(value.ToString(), underlyingType)); 
}