“_Application”和“Application”的区别是什么?

9
为什么在使用Word时需要像这样定义变量:

Dim objWord As New Word.Application

Dim Word As Microsoft.Office.Interop.Word._Application

或者

Microsoft.Office.Interop.Word._Application Word;

然后像这样设置它:
Word = New Microsoft.Office.Interop.Word.Application

或者

Word = new Microsoft.Office.Interop.Word.Application();

Application_Application有什么区别?

我猜想一个可能是类,另一个可能是接口,或者一个是公共的,另一个是私有的,但这对我来说仍然毫无意义。

我希望有人能解释一下。详情越多越好。


应用程序继承自_Application(https://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook.application.aspx),并添加了ApplicationEvents_11_Event。 - the_lotus
@rory,你刚刚制造了一个无限循环!我点击了你的链接,它带我来到我的问题,所以我又点击了你的链接,又回到了我的问题... - John
@rory,如果你还没有弄清楚,我在发帖之前已经搜索过了,而且我总是这样做。这通常可以更快地得到答案。然而,你发布的结果不太清楚。我知道如果有人理解某些东西,他们可能会难以理解什么是清晰的解释,什么不是。幸运的是,Dirk非常有帮助。 - John
我实际上无法相信人们会在这里花时间回答这个问题,这只是一个谷歌搜索,根本不涉及具体的编程问题。我们帮助那些遇到困难的人解决特定的问题,而你并没有遇到任何问题 - Trevor
@Zaggler:我认为Hans的回答证明了你的评论是错误的。我敢打赌你不会轻易地找到那么深入的信息。 - Dirk Vollmar
显示剩余2条评论
2个回答

16

两者都是接口,Application 接口继承自 _Application 接口(还包括 ApplicationEvents4_Event 接口)。

那么何时使用哪个?MSDN 中已经解释了区别(重点标出):

Application interface

[GuidAttribute("00020970-0000-0000-C000-000000000046")]
public interface Application : _Application, 
    ApplicationEvents4_Event

这是一个从COM coclass派生出来的.NET接口,用于与相应的COM对象进行交互以便于托管代码。使用此派生接口访问COM对象的所有方法、属性和事件成员。但是,如果您想要使用的方法或事件在同一COM对象下具有相同的名称,请转换为相应的主要接口以调用该方法,并转换为最新的事件接口以连接到事件。请参阅此主题以获取有关COM对象的信息。 _Application接口:
[TypeLibType(4304)]
[Guid("00020970-0000-0000-C000-000000000046")]
[ComImport]
public interface _Application  { ... }

这是一个COM coclass中的主要接口,用于与相应的COM对象进行互操作所需的托管代码。只有当您想使用的方法与COM对象的事件名称相同时,才使用此主要接口;在这种情况下,将其转换为此接口以调用方法,并转换为最新的事件接口以连接到事件。否则,请使用从COM coclass派生的.NET接口来访问COM对象的方法、属性和事件。
实际后果如下:在您的代码中使用Application而不是_Application,除非由于方法名和事件名之间存在歧义而不得不这样做。
在编程中存在一个歧义,例如Application.Quit事件(当应用程序退出时触发)和Application.Quit(ref Object SaveChanges, ref Object OriginalFormat, ref Object RouteDocument)方法(调用时退出应用程序)之间的歧义。

为了调用该方法,你可以简单地编写以下内容(例如,不提示保存更改即退出):

Application.Quit(false);

然而,这可能会导致编译器警告:
警告3:方法'Microsoft.Office.Interop.Word._Application.Quit(ref object,ref object,ref object)'和非方法'Microsoft.Office.Interop.Word.ApplicationEvents4_Event.Quit'之间的歧义。使用方法组。
为了避免警告,您可以将应用程序对象转换为“_Application”接口。
((_Application)Application).Quit(false); 

如果您想订阅事件,您需要将应用程序对象转换为适当的事件接口:
((ApplicationEvents4_Event)Application).Quit += OnApplicationQuit;

private void OnApplicationQuit()
{
    // handle event here
}

很棒的答案。简短、精确、有用。 - JayC667

12

这个故事还是有点长的,但速度却飞快。COM使用超纯净的基于接口的范式。客户端应用程序只能在接口成员上进行调用,实现接口的“coclass”完全隐藏不可见。暴露出来的只有coclass的guid,CLSID。将这个guid传递给通用的CoCreateInstance()工厂函数,它会返回你所要求的接口。这种隔离是COM服务器可以用任何语言编写的主要原因,因为其实现细节都不可见,所以永远不会与你使用的任何语言不兼容。

然而,使用接口在早期的VB版本中存在问题,与VB.NET不同,它们没有对接口提供任何支持。因此,它们的运行时支持对其进行了操作,并使其看起来像是在使用类。在本例中命名为Application。该类的成员是默认接口_Application的成员。任何来自默认源接口的连接点都被添加为事件。

_Application中的前导下划线也是一个技巧,它告诉类型库浏览器隐藏接口。Visual Studio中的对象浏览器无法做到这一点,这可能是你提出这个问题的原因之一。这种技巧无法解决实现多个接口的coclass的问题。但类型设计者注意到了这一点,他确保将coclass只赋予一个默认接口和一个源接口。

类似的技巧也是为了给.NET程序员提供相同类型的api,确保他们也可以使用Application并轻松地移植他们的代码。这是由类型库导入器(Tlbimp)完成的,它合成了一个与coclass相同名称的额外接口,其所有成员都与默认接口完全相同。

这是一个接口,VB.NET和C#编译器允许您创建它的实例。这与普通接口可做的事情非常不同。导入程序还合成了一个同名类,其名称为coclass加上“Class”。因此,这里是ApplicationClass。它实现了coclass实现的所有接口。在VB.NET中,您没有实际使用它的必要,并且应该避免使用它,因为非常理想的“嵌入Interop类型”功能不支持嵌入它。但是,在像F#这样的语言或被移植到.NET但不支持接口的语言中可能希望使用它。

总之,_Application是来自类型库的实际接口。但是您应该更喜欢合成的Application,最适合所有代码示例。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接