解决方法:Unable to cast COM object of type 'Shell32.ShellClass' to interface 'Shell32.IShellDispatch5'

本文介绍了一种在不同操作系统上获取本地所有网络连接名称的方法,特别解决了从Visual Studio调用Interop.Shell32.dll时遇到的版本兼容性问题。

场景回顾:

我需要做一个功能,很简单,就是显示出本地所有的网络连接

比如在我的网络连接里有以下的items。

代码里需要引用:Interop.Shell32.dll 这个dll

解决方案:

VS 里面的Interop.Shell32.dll(1.0) 这个版本太低了,需要重新到别的网站下过比这个高的版本(我使用的是1.2.107.0)

解决过程:

我下面的代码就是找出所有上面的网络连接名字(有些人会推荐叫我用WMI,对 这个找出这个很easy,但是WMI 没法做我的一些进一步的需求。)

            Shell32.Shell shell = new Shell32.ShellClass();
            Shell32.Folder folder = shell.NameSpace(49);

            foreach (Shell32.FolderItem myItem in folder.Items())
            {
                listBox1.Items.Add(myItem.Name);
            }

然后 开始测试,因为我用的是Win 7 +VS 2010 所有结果很perfect ,看下图:

看,上面全部出来了。很正确,很开心,然后我就到XP 系统下面测试,悲剧了出现了下面的exception,

没办法啦,只好baidu或者google咯,就在老外的一篇文章中知道说到:Since I was developing under Vista, the RCW naturally assumed I wanted the latest interface (Shell32.IShellDispatch5). Windows XP only supports the Shell32.IShellDispatch4 interface.

指的是老外在Vista环境做的开发,因为Vista版本比XP的高,所以Xp不支持Shell32.IShellDispatch5,只支持Shell32.IShellDispatch4,ok,我进行转换了,

 var shell = (Shell32.IShellDispatch4)new Shell32.ShellClass();

可结果还是不行。

后来,想起是不是版本问题???、然后去重新下载了新的版本。。

我下来之后,有2个版本,在VS2010里的用的是第一个版本。请看:

后来我换成1.2.107 这个版本的,然后就ok啦。。

原因也就是上面的老外说的,版本问题。


<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
<think>We are given a specific exception: System.InvalidCastException: Unable to cast object of type 'System.Data.DataTable' to type 'System.IConvertible' This exception typically occurs when we try to convert a DataTable to a type that it doesn't support, such as when using Convert.ToInt32, Convert.ToString, etc. on a DataTable object. Let's break down the problem: We are trying to cast a DataTable object to a type that implements IConvertible (like int, string, etc.), but DataTable does not implement IConvertible, hence the exception. Common scenarios where this might occur: 1. Attempting to read a cell value from a DataRow and convert it to a specific type, but by mistake, we are using the entire DataTable instead of a specific row and column. 2. When using a method that expects a primitive type or string, but we pass a DataTable by mistake. How to fix: We need to ensure that we are accessing the data from the DataTable correctly. We should be accessing a specific row and then a specific column to get the value that we want to convert. Example of incorrect code that might cause this: ```csharp DataTable table = GetDataTable(); // returns a DataTable int id = Convert.ToInt32(table); // This will throw InvalidCastException ``` Instead, we should do: ```csharp // Assuming we want the first row's first column value if (table.Rows.Count > 0) { object value = table.Rows[0][0]; int id = Convert.ToInt32(value); } ``` However, note that the value in the cell might be null or a different type. We should also handle DBNull and other conversion issues. Another approach is to use the Field<T> extension method which provides a cleaner way and handles nulls: ```csharp if (table.Rows.Count > 0) { int? id = table.Rows[0].Field<int?>(0); // if the column is nullable // or int id = table.Rows[0].Field<int>(0); // if the column is not nullable } ``` But note: the original exception is about casting the entire DataTable, so we must check our code to see where we are using the DataTable in a conversion and change it to use the appropriate row and column. Let's write a code example that demonstrates the correct way to extract data from a DataTable and convert it to a desired type. Example scenario: We have a DataTable that has one row and one column named "ID" of type integer. We want to get the ID as an integer. Correct code: ```csharp DataTable table = GetDataTable(); // method that returns a DataTable // Check if there is at least one row if (table.Rows.Count > 0) { DataRow firstRow = table.Rows[0]; // Using column name is safer than index int id = Convert.ToInt32(firstRow["ID"]); // Or using the Field extension method (recommended) int id2 = firstRow.Field<int>("ID"); } else { // Handle the case when there are no rows Console.WriteLine("No rows found."); } ``` However, if the value in the column is DBNull, Convert.ToInt32 will return 0, but the Field method will throw if we use non-nullable type and the value is DBNull. So we can use nullable: ```csharp int? idNullable = firstRow.Field<int?>("ID"); if (idNullable.HasValue) { // use idNullable.Value } ``` Now, if the original exception is happening in a line of code that we have, we must change that line to access the data correctly. If we are not sure where the error is, we should look for any place where a DataTable is being used in a conversion (like Convert.ToInt32, (int), etc.) and replace it with the correct row and column access. Let me provide a more complete example: Suppose we have a method that returns a DataTable and we are trying to use that DataTable as if it were a single value. We must refactor to extract the value. Example of fixing the issue: Before: ```csharp DataTable result = ExecuteQuery("SELECT COUNT(*) FROM Employees"); int count = (int)result; // This is wrong and will throw InvalidCastException ``` After: ```csharp DataTable result = ExecuteQuery("SELECT COUNT(*) AS EmployeeCount FROM Employees"); int count = 0; if (result.Rows.Count > 0) { count = result.Rows[0].Field<int>("EmployeeCount"); } ``` Or if we are using ExecuteScalar for a single value, we might not need a DataTable at all. We can use command.ExecuteScalar() which returns the first column of the first row as an object. Example: ```csharp using (SqlCommand cmd = new SqlCommand("SELECT COUNT(*) FROM Employees", connection)) { int count = (int)cmd.ExecuteScalar(); } ``` So, if the query returns a single value, using ExecuteScalar is more efficient and avoids the DataTable. Conclusion: The exception occurs because we are trying to convert a DataTable (which is a collection of rows and columns) to a simple type that implements IConvertible. The solution is to access the specific cell in the DataTable that contains the value we want, and then convert that cell's value. Let's write a code example that shows how to properly handle a DataTable to avoid this exception.</think>### 解决 `System.InvalidCastException: Unable to cast object of type 'System.Data.DataTable' to type 'System.IConvertible'` #### 问题原因 此异常发生在尝试将 `DataTable` 对象强制转换为 `IConvertible` 类型(如 `int`、`string` 等)时。`DataTable` 本身不实现 `IConvertible` 接口,因此无法直接转换。常见场景包括: 1. 错误地将整个 `DataTable` 当作单值使用(如 `Convert.ToInt32(dt)`)。 2. 未正确访问 `DataTable` 中的单元格值(如 `dt.Rows[0][0]`)。 --- ### 解决方案与代码示例 #### 正确访问 `DataTable` 数据 需明确访问 `DataTable` 中的具体行和列值: ```csharp using System; using System.Data; public class DataTableExample { public static void Main() { // 创建示例 DataTable DataTable dt = new DataTable("Users"); dt.Columns.Add("ID", typeof(int)); dt.Columns.Add("Name", typeof(string)); dt.Rows.Add(1, "Alice"); dt.Rows.Add(2, "Bob"); // 正确获取第一行第一列的值 if (dt.Rows.Count > 0) { // 方法1:使用 Convert 转换 int id1 = Convert.ToInt32(dt.Rows[0]["ID"]); Console.WriteLine($"ID (Convert): {id1}"); // 方法2:使用 Field<T> 扩展方法(推荐) int id2 = dt.Rows[0].Field<int>("ID"); string name = dt.Rows[0].Field<string>("Name"); Console.WriteLine($"ID (Field<T>): {id2}, Name: {name}"); } else { Console.WriteLine("No rows found."); } } } ``` #### 关键点说明 1. **避免直接转换 `DataTable`** 整个 `DataTable` 对象无法转换为简单类型(如 `int`/`string`),必须访问其内部数据。 2. **安全访问数据** - 检查 `dt.Rows.Count > 0` 避免空行异常。 - 使用 `Field<T>("ColumnName")` 方法: - 自动处理类型转换。 - 支持可空类型(如 `Field<int?>("Column")`)。 - 避免手动转换错误。 3. **处理空值** 若列可能为 `DBNull`,使用可空类型: ```csharp int? age = dt.Rows[0].Field<int?>("Age"); if (age.HasValue) { Console.WriteLine(age.Value); } ``` --- ### 常见错误场景修复 #### 错误代码示例 ```csharp DataTable dt = GetData(); int total = Convert.ToInt32(dt); // 抛出 InvalidCastException ``` #### 正确修复 ```csharp DataTable dt = GetData(); if (dt.Rows.Count > 0) { int total = dt.Rows[0].Field<int>("TotalCount"); } ``` --- ### 总结 - **根本原因**:`DataTable` 不是 `IConvertible` 类型。 - **解决方案**: 通过行索引和列名/索引访问具体值,使用 `Field<T>()` 或 `Convert` 方法转换。 - **最佳实践**: 始终检查 `Rows.Count` 和 `DBNull`,优先使用 `Field<T>()`。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值