深入理解 c# 第十一章 Cast,OfType和显式类型的范围变量

本文介绍了在C#中如何使用Cast和OfType操作符处理非类型化的序列。Cast将每个元素转换为目标类型,而OfType则先测试元素类型再进行转换,避免了因类型不匹配导致的异常。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    class CastAndOfType
    {
        static void Main()
        {
            ArrayList list = new ArrayList { "First", "Second", "Third"};
			//list Count=3
			//list列表只包含字符串,可以放心地使用Cast<string>来获得一个
			//字符串序列
            var strings = list.Cast<string>();
			//strings{System.Linq.Enumerable.CastIterator<string>}

            foreach (string item in strings)
			//先strings 后 in  后 stinrg item 初始为null
			//"First",
			//"Second"
			//"Third"
            {
                Console.WriteLine(item);
            }


            list = new ArrayList { 1, "not an int", 2, 3};
			//list Count = 4
			//这个List包含混杂的内容,所以为了从中只获取整数,只能用
			//OfType<int>  如果使用Cast<int>,那么尝试把"not an int"
			//转换为int的时候,会抛出一个异常。这个异常只会发生在打印出
			//"1"之后---两个操作符都对数据进行流处理,在获取元素的时候
			//才对其转换。
            var ints = list.OfType<int>();
			//ints {System.Linq.Enumerable.OfTypeIterator<int>}
            foreach (int item in ints)
			//先foreach, 后ints 后 in 后 int item
			//item 多次赋值
			//1
			//2  "not an int"跳过了
			//3
            {
                Console.WriteLine(item);
            }
        }
    }


Cast,OfType和显式类型的范围变量

  大多数时候,范围变量都可以是隐式类型。可能使用所需类型全部指定了的
泛型集合。如果相对一个ArrayList或一个object[]执行查询,假如LINQ不能
处理这种情况,有两个标准查询操作符来解决这个问题:Cast和OfType。
  只有Cast是查询是查询表达式语法直接支持的。
  这两个操作符很相似:都可以处理任意非类型化的序列,并返回强类型的序列。
Cast通过把每个元素都转换为目标类型(遇到不是正确类型的任何元素的时候,
就会出错)来处理,而OfType首先进行一个测试,以跳过任何具有错误类型的
元素。

  OfType和Cast作为 Enumerable中的一个简单的扩展方法来使用。


输出
First
Second
Third
1
2
3

<think>我们正在处理一个类型转换错误:无法将System.Decimal对象转换为System.Double类型。在C#中,DecimalDouble是两种不同的浮点类型,Decimal具有更高的精度更大的范围,通常用于财务计算,而Double是双精度浮点数,范围较小但性能更好。由于它们是不同的类型,直接强制转换会导致InvalidCastException。 错误示例: ```csharp object obj = 123.456m; // 这是一个Decimal double d = (double)obj; // 这里会抛出InvalidCastException ``` 解决方案: 1. 首先,我们需要确认变量的运行时类型。如果对象是Decimal,我们不能直接将其强制转换为Double,但可以通过Convert.ToDouble()方法或地将Decimal值转换为Double。 2. 使用Convert.ToDouble()方法: ```csharp object obj = 123.456m; double d = Convert.ToDouble(obj); // 如果obj是Decimal,则将其转换为double ``` 3. 如果已知对象是Decimal,可以先将其拆箱为Decimal,然后再转换为Double: ```csharp object obj = 123.456m; double d = (double)(decimal)obj; ``` 4. 注意:直接使用`(double)obj`会失败,因为拆箱操作要求目标类型与装箱类型完全一致(除了允许的基元数值转换,但Decimal到Double不属于这种允许的转换)。所以我们需要先拆箱为Decimal,再转换为Double。 5. 另外,也可以使用as操作符进行尝试,但as操作符只能用于引用类型或可空类型,而Double是值类型,所以不能直接使用as。因此,我们通常使用Convert类或转换。 6. 如果对象可能为null,需要做空值检查: ```csharp if (obj != null) { double d = Convert.ToDouble(obj); } ``` 7. 如果对象可能不是Decimal类型,而是其他可转换为Double的类型(如int, float, string等),那么Convert.ToDouble()方法可以处理多种类型,而转换则需要更多条件判断。 8. 使用类型检查: ```csharp if (obj is decimal) { double d = (double)(decimal)obj; } else if (obj is double) { double d = (double)obj; } // 其他类型... ``` 9. 使用TryParse方法:如果对象是字符串,则可以使用Double.TryParse方法。但这里我们的对象是Decimal,所以不适用。 10. 总结:最安全且简洁的方法是使用Convert.ToDouble(),因为它内部会处理各种类型转换(包括数值类型字符串等)。如果确定对象是数值类型,但不确定具体类型,Convert.ToDouble()是一个好选择。 示例代码: ```csharp object obj = 123.456m; try { double d = Convert.ToDouble(obj); Console.WriteLine($"转换成功: {d}"); } catch (FormatException) { Console.WriteLine("对象不是有效的数字格。"); } catch (InvalidCastException) { Console.WriteLine("无法转换的类型。"); } ``` 注意:Convert.ToDouble()在遇到不能转换的类型时会抛出异常,因此需要适当处理异常。 如果性能要求较高且已知对象主要是Decimal类型,可以先判断类型再转换以避免异常的开销: ```csharp if (obj is decimal dec) { double d = (double)dec; } else { // 其他类型处理 } ``` 根据上述分析,我们可以选择合适的方法来解决转换问题。 相关问题: 1. 在C#中,DecimalDouble的主要区别是什么? 2. 如何避免在类型转换时抛出InvalidCastException? 3. 在C#中,如何安全地将字符串转换为数值类型? 4. 装箱拆箱在C#中是如何工作的? 5. 使用Convert类进行类型转换有什么优缺点?</think>### C# 类型转换错误解决方案:无法将 `System.Decimal` 转换为 `System.Double` #### 错误原因分析 在 C# 中,`decimal` `double` 是两种**不同的浮点类型**,直接强制转换会引发 `InvalidCastException`。核心原因包括: 1. **类型不兼容**:`decimal` 是高精度十进制类型(128 位),而 `double` 是二进制浮点类型(64 位),两者存储方不同。 2. **装箱/拆箱规则**:当 `decimal` 值被装箱为 `object` 类型时,拆箱操作**必须使用完全相同的目标类型**(即 `decimal`),否则会报错。 #### 解决方案 以下是四种可靠方法(按推荐顺序排列): --- ### ✅ 方法 1:使用 `Convert.ToDouble()`(推荐) 直接调用转换方法,适用于 `object` 或 `decimal` 类型: ```csharp object obj = 123.456m; // 装箱的 decimal double result = Convert.ToDouble(obj); // 自动处理转换 ``` --- ### ✅ 方法 2:类型转换 先拆箱为 `decimal`,再转换为 `double`: ```csharp object obj = 123.456m; double result = (double)(decimal)obj; // 拆箱后转换 ``` --- ### ✅ 方法 3:使用 `as` 运算符(需判空) 结合类型检查转换: ```csharp object obj = 123.456m; double? result = (obj as decimal?) as double?; // 通过可空类型中转 if (result.HasValue) { // 使用 result.Value } ``` --- ### ✅ 方法 4:安全类型检查 使用 `is` 运算符确保类型安全: ```csharp object obj = 123.456m; if (obj is decimal decValue) { double result = (double)decValue; // 安全转换 } ``` --- ### 🚫 错误示例(避免!) ```csharp object obj = 123.456m; double d = (double)obj; // ❌ 抛出 InvalidCastException ``` --- ### 关键区别:`decimal` vs `double` | 特性 | `decimal` | `double` | |--------------|--------------------------------|-----------------------| | **精度** | 28-29 位小数(高精度) | 15-16 位小数 | | **范围** | ±1.0 × 10⁻²⁸ 到 ±7.9 × 10²⁸ | ±5.0 × 10⁻³²⁴ 到 ±1.7 × 10³⁰⁸ | | **适用场景** | 财务计算、精确小数 | 科学计算、性能敏感场景 | | **存储** | 128 位 | 64 位 | > 💡 **设计建议**: > 若需混合使用 `decimal` `double`,建议在数据源头统一类型(如数据库字段类型),或使用 `decimal.ToDouble()` 转换[^1]。 --- ### 相关问题 1. 如何在 C# 中安全处理装箱值类型类型转换? 2. `decimal` `double` 在内存占用计算性能上有何差异? 3. 为什么 C# 不允许直接拆箱到不同的数值类型? 4. 在数据库交互时如何避免 `decimal`/`double` 转换错误? 5. 如何通过反射动态转换未知数值类型? [^1]: C# 语言规范要求拆箱操作必须与原始装箱类型完全匹配,否则引发 `InvalidCastException`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值