c#泛型方法以函数为参数

c#泛型方法以函数为参数,c#,generics,methods,functional-programming,extension-methods,C#,Generics,Methods,Functional Programming,Extension Methods,我试图理解一种将两个或多个扩展方法作为参数传递给另一个方法并返回值的方法。对于每个数据类型,我都有扩展方法来返回一个值或默认值、一个值或一个空值以及一个值或抛出一个错误。代码中有需要每种测试的场景,但也有在三元测试中结合每种测试结果的场景,示例如下 public static int IntOrError(this object val, string fieldName) { int test; if (string.IsNullOrEmpty(val.ToString())

我试图理解一种将两个或多个扩展方法作为参数传递给另一个方法并返回值的方法。对于每个数据类型,我都有扩展方法来返回一个值或默认值、一个值或一个空值以及一个值或抛出一个错误。代码中有需要每种测试的场景,但也有在三元测试中结合每种测试结果的场景,示例如下

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"));
像这样的

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);
}
publicstatict转换(此对象输入)
{
if(typeof(T)=input.GetType())
返回(T)输入;
var stringValue=input.ToString();
var converter=TypeDescriptor.GetConverter(typeof(T));
if(converter.CanConvertFrom(typeof(string)))
{
return(T)converter.ConvertFrom(stringValue);
}
返回默认值(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);
}
[事实]
公共void TestMethod1()
{
对象测试=1;
对象testString=“123”;
双重测试双重=1.0;
字符串testError=“abc”;
int resultInt=testInt.Convert();
字符串resultString=testString.Convert();
int resultIntString=testString.Convert();
int dbl2int=testDouble.Convert();
Assert.Throws(()=>testError.Convert());
断言。相等(1,resultInt);
Assert.Equal(“123”,resultString);
Assert.Equal(123,resultinString);
Assert.Equal(1,db2int);
}

您的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);
    }
}
公共静态类MyExtensions
{
公共静态T值或错误(此对象值)
{
尝试
{
// http://stackoverflow.com/a/8633/2534462
return(T)Convert.ChangeType(val,typeof(T));
}抓住
{
抛出新异常(“如果你真的想抛出你自己的异常”);
}
}
公共静态T值默认值(此对象值,T默认值)
{
尝试
{
返回值ValueOrError();
}
抓住
{
return defaultValue;//习惯用法:return default(T);
}
}
公共静态T值ORNULL(此对象val)
{
尝试
{
返回值ValueOrError();
}
抓住
{
//检查可为空的类型
//https://msdn.microsoft.com/de-de/library/ms366789.aspx
var类型=类型(T);
if(type.IsGenericType&&type.GetGenericTypeDefinition()==typeof(可为空))
{
返回默认值(T);//可为null的类型为null
}否则{
抛出新异常(“仅可在可空类型上调用”);
//我的返回另一个默认值???-1???
}
}
}
公共静态T ValueDefaultValidated(此对象值,T defaultValue)
{
返回值ValueOrNull()!=null
?价值评估错误()
:val.valuerDefault(默认值);
}
}
用法

string aNumber=“10”;
var intNumber=aNumber.ValueDefaultValidated(-1);//int
var decNumber=aNumber.ValueDefaultValidated(-1m);//十进制的
字符串naNumber=“无论如何”;
var defaultInt=naNumber.ValueOrDefault(-1);//int
var defaultDecimal=naNumber.ValueDefaultValidated(-1m);
//ValuerNull在不可为空的类型上未定义。
var undefined=naNumber.ValueDefaultValidated(-1m);

我必须对此进行调整,以使错误处理工作相同。在原始版本中,如果有人过去的错误整数为123a。错误扩展方法将抛出它的异常消息,表明它是无效格式。这里的应答逻辑将抛出ValueOrNull异常消息,因此不是完整的一对一替换。
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);