2010-04-29 21 views
5

Im mit aus versuchen, einen Universal-Parsern generischen Typparameter zu machen, aber ich kann das Konzept 100%Allgemeiner Parameter Typ

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

nicht begreifen, wie Sie sich vorstellen können, wird der Code nicht kompiliert werden, da Ich kann int | bool | string nicht in T umwandeln (zB value = valueInt). Dankbar für Feedback, ist es vielleicht nicht möglich, dass ich es mache. Mit .NET 3.5

+0

Wow, gute Frage etwas helfen. Heute Abend, wenn ich Zeit habe, darauf zurückzukommen, werde ich jede glaubwürdige Antwort auflisten. –

Antwort

2

Da, du bist nur eine große große if/then-Combo zu schreiben, ich glaube, Sie mit einem Bündel von Überlastungen besser einfach wäre:

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

ja, das ist der einfache Weg ;-) –

1

Ich habe Parse-Methoden vor der Verwendung einer TypeConverter getan.

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

genagelt es! Danke vielmals! –

+0

obwohl nicht mit ints und bool .. –

1

Dies könnte für Sie arbeiten.

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 und bool sind struct types! – flq

+0

musste den Strukturteil entfernen, damit er funktioniert (wegen der Zeichenfolge, die ich vermute) –

2

Nicht die schönsten Dinge, aber Sie können Ihre T auf etwas anderes werfen, wenn Sie den Zyklus über das Objekt zu tun, das heißt zuerst gegossen zu T auf Objekt dann, oder umgekehrt. Ich sage nichts darüber, ob Sie in Boxing/Unboxing-Sachen kommen, aber der Compiler wird dies akzeptieren.

1

Das Problem ist, dass Sie versuchen, etwas zu machen Generika, die wirklich nicht ist. Selbst wenn Sie jeden Typ manuell durchlaufen, den Sie selbst parsen können, wird dies nicht für alle Typen gelten.

Warum versuchst du das nicht stattdessen? Zunächst einen Delegaten definieren, die eine allgemeine TryParse Methode beschreibt:

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

Dann restrukturieren Ihre Methode eine von diesen als Parameter zu nehmen:

// 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; 
} 
Jetzt

, dies den Standardtypen für alle Überlastung ist ziemlich 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); 
} 

Und so weiter.

Das Schöne an diesem Ansatz ist, dass es Sie nicht einmal auf die Verwendung einer where T : struct-Einschränkung oder sogar auf die integrierten .NET-Typen beschränkt. Ein Benutzer dieser Parser-Klasse kann seine eigenen benutzerdefinierten Typen aus einem XML-Dokument analysieren, indem er einfach eine TryParse-ähnliche Methode für seine benutzerdefinierten Typen definiert.

4

Die Klassen XElement und XAttribute bieten beide a set of explicit conversion operators (Umwandlungen), um ihre Inhalte bequem in primitive .NET-Typen konvertieren zu können.

Zum Beispiel können Sie einfach tun:

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, gut zu wissen. –

+0

brillanter Fang. –

1

Diese Methode, die ich in der Vergangenheit verwendet haben könnte

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