如何确定null值是System.String还是System.Nullable <int>

时间:2018-01-10 14:15:46

标签: c#

我有一个简单的方法,我将属性传递为arg。然后我尝试确定返回字符串,int或decimal的格式。这是方法。

    protected T GetValue<T>(T arg, List<string> item, int index)
    {
        if ((object)arg == null)
            return (T)(object)Convert.ToInt32(item[index]);//throws specified cast not valid

        if (arg.GetType() == typeof(int))
            return (T)(object)Convert.ToInt32(item[index]);

        if (arg.GetType() == typeof(string))
            return (T)(object)arg.ToString();

        if (arg.GetType() == typeof(decimal))
            return (T)(object)Convert.ToDecimal(item[index]);

        return default(T);
    }

问题在于,当我将arg作为System.String或System.Nullable传入时,它们都是空的。因此,当我对字符串执行specified cast invalid而对可空的int执行Convert.ToInt32(item[index])时,我得到arg.ToString()

3 个答案:

答案 0 :(得分:3)

当只有少数不相关的类型可能没有共同点时,不要使用泛型。 stringintdecimal是完全不同的类型,除了调用他们的ToString - 方法和从{object继承的其他一些方法之外,没有什么可以做的。 1}})。

而是使用三种不同的方法:

protected decimal GetDecimal(decimal arg) { ...}
protected string GetString(string arg) { ...}
protected int GetInt(int arg) { ...}

这样你甚至可以省略arg - 参数,它似乎只作为正确类型的虚拟实例存在,以便进行通用工作。因此,无论如何你必须在编译时知道正确的类型,所以你也可以通过选择正确的方法直接提供它。

如果你真的 使用泛型,请使用is - 运算符:

protected T GetValue<T>(T arg, List<string> item, int index)
{
    if (arg is int)
        return (T)(object)Convert.ToInt32(item[index]);

    if (arg is string)
        return (T)(object)arg.ToString();

    if (arg is decimal)
        return (T)(object)Convert.ToDecimal(item[index]);

    return default(T);
}

然而,这不是用于制作泛型的。

答案 1 :(得分:3)

你的方法根本不应该是通用的。这就是重载:

protected object GetValue(
    object arg, List<string> item, int index)
{
    if (arg == null)
        //...
    else
        //whatever seems fit for an object that isn't resolved to
        //another overload
}

protected string GetValue(
    string arg, List<string> item, int index)
{
     return arg; //hmmm, how useful is this?
}

protected decimal GetValue(
     decimal arg, List<string> item, int index)
{
     return Convert.ToDecimal(item[index]);
}

protected int GetValue(
    int arg, List<string> item, int index)
{
     return Convert.ToInt32(item[index]);
}

效果更好。当有效类型是有限集时,不要使用泛型。泛型应该适用于符合某些constaints的任何类型T

通常,如果您在通用方法中开始需要运行时类型检查,那么您做错了什么!

更新:遵循Servy的评论,如果您需要支持可空的整数,小数等,那么只需编写相应的重载。不过我想在以下情况中指出:

int? i = null;
var result = GetValue((object)i);

如果参数GetValue实际上是arg,可以为空的值类型或对象,则无法识别string内部。除了知道参数是静态类型null之外,object没有您可以利用的类型信息。

这显然是非常不同的:

protected int? GetValue(int? arg, List<string> item, int index) { ... }

int? i = null;
var result = GetValue(i);

此处arg也是null,但已解决的重载为GetValue(int? arg),因此您知道 arg是可空的int }。

答案 2 :(得分:0)

可悲的是,我无法理解您发布的代码,但我尽力为您提供有效的解决方案。

在本质上,为什么不在列表中装入对象,然后使用类型参数调用方法,而不是滥用这样的泛型。 这样的事情可以解决问题:

protected T GetValue<T>(List<object> item, int index) {
    if (index > item.Count || item[index] is default)
        throw new ArgumentException("Very detailed message");
    else if (item[index] is T val)
        return val;
    else
        return (T)item[index]; // Will stil throw an exception if cast fails
        // Of course you can add different/more checks
}