c#泛型方法将函数作为参数

c# generic method take function as param

我正在尝试了解一种将两个或多个扩展方法作为参数传递给另一个方法并 return 返回值的方法。我有每个数据类型的扩展方法 return 一个值或默认值和一个值或一个空值以及一个值或抛出错误。该代码具有需要这些中的每一个的场景,但它也有在三元测试中组合每个这些的结果的场景,示例如下。

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

我正在尝试获取一个通用方法或一种函数式方法,它将扩展方法作为参数并 return 返回值。

我希望尽可能避免反射。

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

是这样的吗?

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

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

public static class MyExtensions
{
    public static T ValueOrError<T>(this object val)
    {
        try
        {
            // 
            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);