尝试包装 COM 接口以便它们可识别时出现意外的 C# 编译器错误

本文关键字:意外 错误 编译器 识别 COM 包装 接口 | 更新日期: 2023-09-27 18:34:57

(注意:我声称这不是使用IDisposable清理Excel互操作对象的副本。这个问题问"我该怎么做?我的主要问题是"为什么我会收到 C# 编译器错误?

此处的主要目标是从 C# 程序中读取(和稍后写入(Excel 文件。Google建议我应该添加对Microsoft.Office.Interop.Excel的引用并从那里运行。我看到了足够的代码,知道我正在执行 COM 互操作,因此我想在完成 COM 对象后释放它们。添加引用(Visual Studio 2012中Microsoft.Office.Interop.Excel的14.0.0.0版本(后,我将开始比赛。

现在,我不相信自己记得在所有正确的位置获取对Marshal.ReleaseComObject的所有调用,因此我想将我的 COM 对象放入using语句中。 Microsoft.Office.Interop.Excel.Application不是IDisposable,而且,据我所知,Microsoft.Office.Interop.Excel命名空间中的任何其他内容也没有。但没关系。我很聪明。我知道如何解决这个问题:

using Excel = Microsoft.Office.Interop.Excel;
//...
sealed class ExcelWrapper<T> : IDisposable
{
    public T Child { get; private set; }
    public ExcelWrapper(T child) { Child = child; }
    public static implicit operator ExcelWrapper<T>(T child) { return new ExcelWrapper<T>(child); }
    public static implicit operator T(ExcelWrapper<T> host) { return host.Child; }
    public void Dispose()
    {
        try { Marshal.ReleaseComObject(Child); }
        catch { }
    }
}
//...    
using (ExcelWrapper<Excel.Application> _xlApp = (ExcelWrapper<Excel.Application>)new Excel.Application()) // CS0030
{
    Excel.Application xlApp = _xlApp; // CS0029 and CS0266
}

这给我带来了我不明白的错误消息(上面的注释指出了有错误的行(:

 error CS0030: Cannot convert type 'Microsoft.Office.Interop.Excel.Application' to 'ExcelWrapper<Microsoft.Office.Interop.Excel.Application>'
 error CS0029: Cannot implicitly convert type 'ExcelWrapper<Microsoft.Office.Interop.Excel.Application>' to 'Microsoft.Office.Interop.Excel.Application'

为什么我会收到这些错误消息?我没有输入public static implicit operator吗?出于某种原因,我尝试了解封ExcelWrapper.事情发生了变化,但我仍然不明白发生了什么:

error CS0266: Cannot implicitly convert type 'ExcelWrapper<Microsoft.Office.Interop.Excel.Application>' to 'Microsoft.Office.Interop.Excel.Application'. An explicit conversion exists (are you missing a cast?)

我仍然很确定存在隐式转换。但是我可以通过使用显式转换来安抚编译器,只要我可以不密封ExcelWrapper

那么,我在这里做错了什么?

为什么当ExcelWrapper类被密封时,编译器似乎完全忽略了我的转换运算符?为什么当ExcelWrapper类未密封时,编译器似乎忽略了implicit指定(而不是运算符的其余部分(?

尝试包装 COM 接口以便它们可识别时出现意外的 C# 编译器错误

语言规范的第 10.9.3 节指出:

转换运算符从源类型转换,由 转换为目标类型的转换运算符的参数类型,指示 按转换运算符的返回类型。类或结构是 允许声明从源类型 S 到目标的转换 键入 T,前提是满足以下所有条件:

- S and T are different types.
- Either S or T is the class or struct type in which the operator declaration takes place.
- Neither S nor T is object or an interface-type.
- T is not a base class of S, and S is not a base class of T.

Excel.Application 是一种接口类型,这就是无法创建隐式转换的原因。

该规范的在线版本有点过时,您的安装目录中有一个更新的版本。 转换规则的新部分是 10.10.3 。 对于VS 2013,规范位于:

C:'Program Files (x86)'Microsoft Visual Studio 12.0'VC#'Specifications'1033

在更新的版本中,还有一个声明:

  • 如果 T 是接口类型,则忽略从 S 到 T 的用户定义隐式转换。

但目前还不完全清楚这是否适用于全球,还是仅在存在从 S 到 T 的显式转换时才适用。