7

decimal?是否有将对象转换为数据类型的单行方式?

我的代码看起来像这样:

foreach(DataRow row in dt.Rows)
{
    var a = new ClassA()
    {
         PropertyA = row["ValueA"] as decimal?,   
         PropertyB = row["ValueB"] as decimal?,
         PropertyC = row["ValueC"] as decimal?
    };

    // Do something

}

但是,将对象转换为 adecimal?并不能按我期望的方式工作,并且每次都返回 null。

数据行是从 Excel 文件中读取的,因此每行中对象的数据类型要么是 a(double如果有值),要么是 null(string如果它留空)。

执行此转换的建议方法是使用decimal.TryParse,但是我不想为类上的每个小数属性创建一个临时变量(我的实际类中有大约 7 个属性是小数,而不是 3 个)。

decimal tmpvalue;
decimal? result = decimal.TryParse((string)value, out tmpvalue) ?
                  tmpvalue : (decimal?)null;

有没有办法可以decimal?在一行中将潜在的空值转换为 a?

我尝试了此处发布的答案,但是它似乎没有工作,并且也给了我一个null值,因为row["ValueA"] as string返回null

4

7 回答 7

6

你最好的选择是创建一个扩展方法。这就是我使用的,尽管您可以调整它以返回 a decimal?

public static class ObjectExtensions
{
    public static decimal ToDecimal(this object number)
    {
        decimal value;
        if (number == null) return 0;
        if (decimal.TryParse(number.ToString().Replace("$", "").Replace(",", ""), out value))
            return value;
        else
            return 0;
    }
    public static decimal? ToNullableDecimal(this object number)
    {
        decimal value;
        if (number == null) return null;
        if (decimal.TryParse(number.ToString().Replace("$", "").Replace(",", ""), out value))
            return value;
        else
            return null;
    }

}

然后,您可以通过调用.ToDecimal()任何对象来使用它,就像调用.ToString().

它不是一行,但它只是在使用它的点上的单个函数调用,并且它是非常可重用的。

编辑添加可空版本

于 2013-01-02T17:40:01.483 回答
4

提供它读取为双精度的值,否则我认为它是一个字符串

好的,所以这使事情变得复杂,因为有时你需要解析它,有时你不需要。

我们要做的第一件事是检查它是否已经是 adouble并转换它,因为转换比解析便宜得多;解析很昂贵。

鉴于这个逻辑将是不平凡的,它属于它自己的方法:

public static deciaml? getDecimal(object rawValue)
{
    decimal finalValue;

    double? doubleValue = rawValue as double?;
    if(doubleValue.HasValue)
        return (decimal) doubleValue.Value;
    else if(decimal.TryParse(rawValue as string, out finalValue))
    {
        return finalValue;
    }
    else
    {
        return null;//could also throw an exception if you wanted.
    }
}

如果您知道它始终是双精度值,并且您永远不会想要字符串值,那么它会更容易。在这种情况下,您首先需要将其转换为双精度类型,因为它是真实类型,然后您可以轻松地将其转换为小数:

PropertyA = (decimal?)(row["ValueA"] as double?);
于 2013-01-02T17:43:12.340 回答
1

decimal.TryParse是要走的路。只需创建一个辅助方法并返回值。您提到的代码几乎相同:

private decimal? convertToNullableDecimal(object value){
  decimal tmpvalue;
  return decimal.TryParse((string)value, out tmpvalue) ? tmpvalue : (decimal?)null;
}

更新

这假设您需要一个可以为空的小数。否则按照其他答案中的建议进行操作,请使用内置方法:Convert.ToDecimal

于 2013-01-02T17:40:24.037 回答
0

你可以试试Decimal.Parse方法。

public static decimal ToDecimal(this string value){

    try
    {
        return Decimal.Parse(value);
    }   
    catch (Exception)
    {
        //  catch FormatException, NullException
        return 0;
    }
}

//  use
PropertyA = row["ValueA"].ToString().ToDecimal();
PropertyB = row["ValueB"].ToString().ToDecimal();
PropertyC = row["ValueC"].ToString().ToDecimal();
于 2013-01-02T17:47:23.533 回答
0

Convert.ToDecimal(object)几乎做你想要的。它将正确转换双精度值(无需先转到字符串),还可以处理其他可以转换为十进制的类型。它做得不好的一件事是空转换(或将 String.Empty 转换为空)。我会尝试使用扩展方法来处理。

public static class ObjectToDecimal
{
  public static decimal? ToNullableDecimal(this object obj)
  {
    if(obj == null) return null;
    if(obj is string && String.Empty.Equals(obj)) return null;
    return Convert.ToDecimal(obj);
  }
}

请记住,这Convert.ToDecimal(object)可能会引发异常,因此您必须注意这一点。

于 2013-01-02T18:14:25.477 回答
0

尝试类似的东西

Func<object, decimal?> l_convert =
    (o) => decimal.TryParse((o ?? "").ToString(), out tmpvalue) ? tmpvalue : (decimal?)null;

var a = new ClassA()
{
     PropertyA = l_convert(row["ValueA"]),   
     PropertyB = l_convert(row["ValueB"]),
     PropertyC = l_convert(row["ValueC"])
};
于 2013-01-02T17:41:01.337 回答
0

希望这可以帮助

decimal temp;
foreach(DataRow row in dt.Rows)
{
    var a = new ClassA()
    {
         PropertyA = Decimal.TryParse(row["ValueA"].ToString(), out temp) ? Convert.ToDecimal(row["ValueA"].ToString()) : (Decimal?) null,   
         ....
    };

    // Do something

}
于 2013-01-02T17:42:36.023 回答