0

Я пытаюсь понять способ передать в двух или более методах расширения другому методу в качестве параметров и вернуть значение обратно. У меня есть методы расширения для каждого типа данных, чтобы вернуть значение или значение по умолчанию, а также значение или нулевое значение, а также значение или выбросить ошибку. В коде есть сценарии, которые потребуют каждого из них, но также имеют сценарии, объединяющие результаты каждого из них в тройном тесте, примеры ниже.C# generic method принимает функцию как 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; 
    } 
} 

Я пытался сделать многоразовый метод, который может обрабатывать принимать в в этом примере 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

Я должен настроить это так, что обработка ошибок работает так же. В оригинале, если кто-то прошёл в плохом int 123a. Метод расширения ошибки выкинул бы сообщение об исключении, что он был недопустимым. Логика ответа здесь вместо этого выведет сообщение ValueOrNull Exception, а не полную замену на один. – 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); 
}