如何在泛型方法中使用<T> .TryParse,而T是double或Int

kas*_*hif 24 c# generics

在我的一个项目中,我正在使用以下两种方法.1. GetDoubleValue和2. GetIntValue.GetDoubleValue使用double.TryParse参数str字符串,如果失败则返回0,而GetIntValue尝试int.TryParse到参数str字符串,如果失败则返回0.我想要的是将这两个方法组合成一个通用方法,与字符串str一起接收参数T,这样如果我想使用GetDoubleValue方法,我可以使用double作为参数T,如果我想使用GetIntValue方法我可以使用Int为参数T

public double GetDoubleValue(string str)
{
    double d;
    double.TryParse(str, out d);
    return d;
}
public int GetIntValue(string str)
{
    int i;
    int.TryParse(str, out i);
    return i;
}
Run Code Online (Sandbox Code Playgroud)

注意:我尝试过这样的事情;

private T GetDoubleOrIntValue<T>(string str) where T : struct 
{
    T t;
    t.TryParse(str, out t);
    return t;
}
Run Code Online (Sandbox Code Playgroud)

编辑

在我的数据库中,我在具有numeric数据类型的不同表中有30多列.如果用户没有在文本框中键入任何内容,我想在每列中插入0,即他将所有或部分文本框留空.如果我不使用GetIntValue方法,我将不得不使用方法体超过30次.这就是我通过方法方法做到这一点的原因.例如,我正在编写三十多个例子中的三个

cmd.Parameters.Add("@AddmissionFee", SqlDbType.Decimal).Value = GetIntValue(tbadmissionfee.Text);
cmd.Parameters.Add("@ComputerFee", SqlDbType.Decimal).Value = GetIntValue(tbcomputerfee.Text);
cmd.Parameters.Add("@NotesCharges", SqlDbType.Decimal).Value = GetDoubleValue(tbnotescharges.Text);
Run Code Online (Sandbox Code Playgroud)

我想结合上述两种方法,因为今天我有两种这样的方法,如果组合起来不会给编程带来更好的改进,但明天我可能会有几十种这样的方法,最好组合成一种通用方法.例如,我可能有GetInt32Value,GetShortValue等希望它现在已经清除,为什么我想要这个?

Lee*_*Lee 10

我会考虑编写扩展或静态方法:

delegate bool TryParse<T>(string str, out T value);

public static T GetValue<T>(this string str, TryParse<T> parseFunc)
{
    T val;
    parseFunc(str, out val);
    return val;
}
Run Code Online (Sandbox Code Playgroud)

然后,您必须提供TryParse要使用的实现:

int i = "1234".GetValue<int>(int.TryParse);
Run Code Online (Sandbox Code Playgroud)

请注意,如果解析失败,此函数将以静默方式返回默认值.default(T)如果TryParse委托返回false,您可能希望返回.

  • +1此方法如下所示:http://geekswithblogs.net/michelotti/archive/2008/10/05/tryparse-extension-methods.aspx我同意在这种情况下它可能有点过分,但作为一般的实用类它可能有用. (2认同)

svi*_*ick 9

我同意Mark Byers的观点.尝试将此方法设为通用可能不是一个好主意.一点点代码重复不会受到伤害(只要它真的只是一点点).您可以使用任何struct通用版本的事实也不会让我看起来像个好主意.

如果你真的想这样做,你可以尝试使用反射(如Minustar建议的那样),但这既丑又慢.

相反,你可以使用Convert.ChangeType():

private T GetValue<T>(string str) where T : struct 
{
    return (T)Convert.ChangeType(str, typeof(T));
}
Run Code Online (Sandbox Code Playgroud)


Mar*_*ers 8

所以不要写:

double d = GetDoubleValue(str);
Run Code Online (Sandbox Code Playgroud)

你想能写这个吗?

double d = GetValue<double>(str);
Run Code Online (Sandbox Code Playgroud)

即使你可以让它工作,有什么好处?我个人并不认为这对客户来说是一个巨大的进步.唯一的优点是不必两次实现相同的方法.但是考虑到方法的简单性以及实现这种类型的代码重用的难度,这里复制那几行代码似乎是合理的.

你并不是唯一遇到这个问题的人.看一下.NET框架中适用于不同类型的其他方法,看看它们是如何解决的.以下是BinaryReader允许您阅读不同类型的方法:

它不漂亮,但这就是通常的方式.


关于您的更新,我还有两点要做.

您提到您可能会有两种以上的类型,这可能会导致相同代码的重复更多.鉴于该方法非常简洁和简单,复制和粘贴代码似乎不是问题.在我看来,不应该复制和粘贴代码的规则是一个合理的例外.虽然在公共接口中仍然需要许多类似命名的方法,但此处的方法可以减少重复的数量.

但是我认为重要的是要提到在你的情况下默默地使用默认值似乎是错误的,正如Lee已在评论中提到的那样.如果用户在输入数据时出错,则应收到错误消息.您应该使用某种验证框架来确保字符串有效,并告知用户如果它们无效则问题是什么.一旦验证了所有内容,就可以安全使用,int.Parse而不是int.TryParse因为您知道解析会成功.如果解析失败,这是一种特殊情况(验证中的错误),因此应用程序通过异常退出并记录堆栈跟踪似乎是公平的.这将帮助您找到并修复错误.


Eri*_*ang 7

你可以这样做:

   public static T GetDoubleOrIntValue<T>(this string str) where T : IConvertible
{
    var thisType = default(T);
    var typeCode = thisType.GetTypeCode();
    if (typeCode == TypeCode.Double)
    {
        double d;
        double.TryParse(str, out d);
        return (T)Convert.ChangeType(d,typeCode) ;
    }
    else if (typeCode == TypeCode.Int32)
    {
        int i;
        int.TryParse(str, out i);
        return (T)Convert.ChangeType(i, typeCode);
    }
    return thisType;
}
Run Code Online (Sandbox Code Playgroud)

然后当你打电话给它:

string d = "1.1";
string i = "3";

double doubleValue = d.GetDoubleOrIntValue<double>();
int intValue = i.GetDoubleOrIntValue<int>();
Run Code Online (Sandbox Code Playgroud)

但整件事对我来说似乎有点傻.

编辑:看到其他人使用Convert.ChangeType ...它提供了泛型返回类型.