0

Ich versuche, einen Weg zu verstehen, in zwei oder mehr Erweiterungs-Methoden zu einer anderen Methode als Parameter übergeben und den Wert zurückgeben. Ich habe Erweiterungsmethoden für jeden Datentyp, um einen Wert oder einen Standardwert und einen Wert oder einen Nullwert und auch einen Wert zurückzugeben oder einen Fehler zu werfen. Der Code enthält Szenarios, für die jeweils eine dieser Szenarien erforderlich ist, aber auch Szenarios, in denen die Ergebnisse der einzelnen Tests in einem ternären Test kombiniert werden (Beispiele unten).C# generische Methode take function as param

public static int IntOrError(this object val, string fieldName) 
{ 
    int test; 

    if (string.IsNullOrEmpty(val.ToString())) 
    { 
     throw new Exception("I threw it"); 
    } 
    else if (int.TryParse(val.ToString(), out test) == false) 
    { 
     throw new Exception("Bad Int Value"); 
    } 
    else 
    { 
     return test; 
    } 
} 

public static int IntOrDefault(this object val) 
{ 
    int test; 

    if (int.TryParse(val.ToString(), out test)) 
    { 
     return test; 
    } 
    else 
    { 
     return -1; 
    } 
} 

public static int? IntOrNull(this object val) 
{ 
    int test; 

    if (int.TryParse(val.ToString(), out test)) 
    { 
     return test; 
    } 
    else 
    { 
     return -1; 
    } 
} 

Ich habe versucht, eine wiederverwendbare Methode zu machen, die in diesem Beispiel IntOrNull, IntOrDefault und IntOrError und übergeben Sie zurück int oder werfen einen Fehler nehmen in verarbeiten konnte. Bisher konnte ich das nur zur Arbeit bringen. Ich versuche zu vermeiden, diese Methode für jeden Datentyp auch zu erstellen.

public static int IntDefaultValidated(this object val, string fieldName) 
{ 
    return val.IntOrNUll() != null 
     ? val.IntOrDefaultError(fieldName) 
     : val.IntOrDefault(); 
} 

Ich versuche, eine generische Methode oder einen funktionellen Stil der Methode zu erhalten, die in den Erweiterungsmethoden wie params und zurück um den Wert zu nehmen.

Ich hoffe, Reflexion zu vermeiden, wenn möglich.

//just a psuedo example 
var intVal = ""; 
var valRet = DefaultValidated(intVal.IntOrNull(), intVal.IntOrdefault(), intVal.IntOrDefaultError("intVal")); 
//or maybe like this, or some combination of extension, generic, functional 
var valRet = intVal.DefaultOrValidated(IntOrNull(intVal), IntOrDefault(intVal), IntOrDefaultError(intVal, "intVal")); 

Antwort

0

Ihre Logik IntOrDefault, IntOrNull und IntDefaultValidated nicht wirklich Sinn machen, so dass ich denke, es ist nur ein Anwendungsbeispiel.
Abgesehen davon - mein Rat ist, Ihre Funktionen als generische Erweiterungen zu implementieren.

public static class MyExtensions 
{ 
    public static T ValueOrError<T>(this object val) 
    { 
     try 
     { 
      // http://stackoverflow.com/a/8633/2534462 
      return (T)Convert.ChangeType(val, typeof(T)); 
     } catch 
     { 
      throw new Exception("Throw your own exception if you really want to"); 
     } 
    } 

    public static T ValueOrDefault<T>(this object val, T defaultValue) 
    { 
     try 
     { 
      return val.ValueOrError<T>(); 
     } 
     catch 
     { 
      return defaultValue; // usally use: return default(T); 
     } 
    } 

    public static T ValueOrNull<T>(this object val) 
    { 
     try 
     { 
      return val.ValueOrError<T>(); 
     } 
     catch 
     { 
      // check for nullable type 
      //https://msdn.microsoft.com/de-de/library/ms366789.aspx 
      var type = typeof(T); 
      if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) 
      { 
       return default(T); // null on nullable types 
      } else { 
       throw new Exception("Callable only on Nullable types"); 
       // my return another default value ??? .. -1 ??? 
      } 
     } 
    } 


    public static T ValueDefaultValidated<T>(this object val, T defaultValue) 
    { 
     return val.ValueOrNull<T>() != null 
      ? val.ValueOrError<T>() 
      : val.ValueOrDefault<T>(defaultValue); 
    } 
} 

Nutzungs

string aNumber = "10"; 
var intNumber = aNumber.ValueDefaultValidated(-1); // int 
var decNumber = aNumber.ValueDefaultValidated(-1m); // decimal 

string naNumber = "whatever"; 
var defaultInt = naNumber.ValueOrDefault(-1); // int 
var defaultDecimal = naNumber.ValueDefaultValidated<decimal?>(-1m); 
// ValueOrNull ist undefined on Non-Nullable-Type. 
var undefined = naNumber.ValueDefaultValidated<decimal>(-1m); 
+0

Ich werde dies so anpassen müssen, dass die Fehlerbehandlung die gleiche funktioniert. Im Original wenn jemand in einem schlechten 123a vorbeigeht. Die Fehlererweiterungsmethode würde die Exception-Nachricht auslösen, dass es sich um ein ungültiges Format handelt. Die Antwortlogik hier wird stattdessen die ValueOrNNull Exception-Nachricht ausgeben, also nicht eine vollständige Eins-zu-eins-Ersetzung. – langc334

0

So ähnlich?

public static T Convert<T>(this object input) 
{ 
    if (typeof (T) == input.GetType()) 
     return (T) input; 

    var stringValue = input.ToString(); 
    var converter = TypeDescriptor.GetConverter(typeof(T)); 
    if (converter.CanConvertFrom(typeof(string))) 
    { 
     return (T)converter.ConvertFrom(stringValue); 
    } 
    return default(T); 
} 

Dieser Test besteht. Vielleicht ist das nicht genau das was du brauchst aber trotzdem.

[Fact] 
public void TestMethod1() 
{ 
    object testInt = 1; 
    object testString = "123"; 
    double testDouble = 1.0; 
    string testWrong = "abc"; 

    int resultInt = testInt.Convert<int>(); 
    string resultString = testString.Convert<string>(); 
    int resultIntString = testString.Convert<int>(); 
    int dbl2int = testDouble.Convert<int>(); 

    Assert.Throws<Exception>(() => testWrong.Convert<int>()); 

    Assert.Equal(1, resultInt); 
    Assert.Equal("123", resultString); 
    Assert.Equal(123, resultIntString); 
    Assert.Equal(1, dbl2int); 
}