【问题标题】:c# generic method take function as paramc#泛型方法以函数为参数
【发布时间】:2016-07-17 12:05:06
【问题描述】:

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

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

【问题讨论】:

    标签: c# generics methods functional-programming extension-methods


    【解决方案1】:

    您的 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);
    

    【讨论】:

    • 我必须对此进行调整,以使错误处理工作相同。在原来的情况下,如果有人过去在 123a 的错误 int 中。错误扩展方法会抛出它的异常消息,它是一种无效的格式。这里的答案逻辑会抛出 ValueOrNull Exception 消息,所以不是完全的一对一替换。
    【解决方案2】:

    这样的?

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多