0

我想了解一种方法来将两个或更多扩展方法传递给另一个方法作为参数并返回值。我有每种数据类型的扩展方法返回一个值或默认值和值或空值,也是一个值或抛出一个错误。代码具有需要其中每一个的场景,但它也具有在三元测试中结合来自每个场景的结果的场景,下面的例子。c#泛型方法作为参数

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

我一直在试图使可能采取处理,在这个例子中IntOrNull,IntOrDefault和IntOrError并传回int或抛出一个错误,可重复使用的方法。到目前为止,我只能得到这个工作。我试图避免为每个数据类型也创建这种方法。

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

我想获得一个泛型方法或函数样式的方法,将采用扩展方法作为参数并返回值。

我希望避免反射,如果可能的话。

//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")); 

回答

0

你IntOrDefault,IntOrNull和IntDefaultValidated的逻辑并没有什么意义,所以我认为这只是一个使用示例。
除此之外 - 我的建议是将您的功能实现为通用扩展。

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

使用

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

我将不得不调整这使得错误处理的工作原理相同。在原来如果有人过去123a的不良整数。错误扩展方法会抛出异常消息,表明它是无效格式。这里的答案逻辑将抛出ValueOrNull异常消息,所以不是完整的一对一替换。 – langc334

0

是这样的吗?

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

该测试通过。可能这不完全是你需要的,但仍然是。

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