Jon*_*eet 167 c# compiler-construction com c#-4.0
编辑:我已将结果写成博客文章.
C#编译器有点神奇地处理COM类型.例如,这个陈述看起来很正常......
Word.Application app = new Word.Application();
Run Code Online (Sandbox Code Playgroud)
......直到你意识到这Application是一个界面.在接口上调用构造函数?Yoiks!这实际上被转换为对Type.GetTypeFromCLSID()另一个的调用Activator.CreateInstance.
此外,在C#4中,您可以对ref参数使用非ref 参数,并且编译器只是添加一个局部变量以通过引用传递,丢弃结果:
// FileName parameter is *really* a ref parameter
app.ActiveDocument.SaveAs(FileName: "test.doc");
Run Code Online (Sandbox Code Playgroud)
(是的,有一堆参数丢失.不是可选参数好吗?:)
我正在尝试调查编译器的行为,我没有假装第一部分.我可以做第二部分没有问题:
using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
[ComImport, GuidAttribute("00012345-0000-0000-0000-000000000011")]
public interface Dummy
{
void Foo(ref int x);
}
class Test
{
static void Main()
{
Dummy dummy = null;
dummy.Foo(10);
}
}
Run Code Online (Sandbox Code Playgroud)
我想能够写:
Dummy dummy = new Dummy();
Run Code Online (Sandbox Code Playgroud)
虽然.显然它会在执行时爆炸,但没关系.我只是在试验.
编译器为链接的COM PIA(CompilerGenerated和TypeIdentifier)添加的其他属性似乎没有做到这一点......什么是神奇的酱油?
Mic*_*tta 144
我绝不是这方面的专家,但最近我偶然发现了我想要的东西:CoClass属性类.
[System.Runtime.InteropServices.CoClass(typeof(Test))]
public interface Dummy { }
Run Code Online (Sandbox Code Playgroud)
coclass提供一个或多个接口的具体实现.在COM中,这种具体实现可以用任何支持COM组件开发的编程语言编写,例如Delphi,C++,Visual Basic等.
请参阅我对有关Microsoft Speech API的类似问题的回答,您可以在其中"实例化"界面SpVoice(但实际上,您正在实例化SPVoiceClass).
[CoClass(typeof(SpVoiceClass))]
public interface SpVoice : ISpeechVoice, _ISpeechVoiceEvents_Event { }
Run Code Online (Sandbox Code Playgroud)
Eri*_*ert 61
在你和迈克尔之间,你几乎把这些东西放在一起.我认为这是它的工作原理.(我没有写代码,所以我可能会稍微误解它,但我很确定这是怎么回事.)
如果:
然后代码生成为(IPIAINTERFACE)Activator.CreateInstance(Type.GetTypeFromClsid(GUID OF COCLASSTYPE))
如果:
然后生成代码就像你说"new COCLASSTYPE()"一样.
乔恩,如果你对这些东西有疑问,请随时给我或Sam直接打扰.仅供参考,Sam是此功能的专家.
Jon*_*eet 36
好吧,这只是为迈克尔的答案提供了更多的内容(如果他愿意的话,欢迎他加入,在这种情况下我会删除这个).
查看Word.Application的原始PIA,涉及三种类型(忽略事件):
[ComImport, TypeLibType(...), Guid("..."), DefaultMember("Name")]
public interface _Application
{
...
}
[ComImport, Guid("..."), CoClass(typeof(ApplicationClass))]
public interface Application : _Application
{
}
[ComImport, ClassInterface(...), ComSourceInterfaces("..."), Guid("..."),
TypeLibType((short) 2), DefaultMember("Name")]
public class ApplicationClass : _Application, Application
{
}
Run Code Online (Sandbox Code Playgroud)
由于Eric Lippert在另一个答案中谈到的原因,有两个接口.正如你所说的那样,就是CoClass类本身和Application界面上的属性.
现在,如果我们在C#4中使用PIA链接,其中一些内容将嵌入到生成的二进制文件中...但不是全部.只创建一个Application以这些类型结束的实例的应用程序:
[ComImport, TypeIdentifier, Guid("..."), CompilerGenerated]
public interface _Application
[ComImport, Guid("..."), CompilerGenerated, TypeIdentifier]
public interface Application : _Application
Run Code Online (Sandbox Code Playgroud)
不ApplicationClass- 可能是因为它将在执行时从真实的 COM类型动态加载.
另一个有趣的事情是链接版本和非链接版本之间的代码差异.如果您反编译该行
Word.Application application = new Word.Application();
Run Code Online (Sandbox Code Playgroud)
在引用的版本中,它最终为:
Application application = new ApplicationClass();
Run Code Online (Sandbox Code Playgroud)
而在链接版本中它最终为
Application application = (Application)
Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid("...")));
Run Code Online (Sandbox Code Playgroud)
所以它看起来像"真实" PIA需要的CoClass属性,但链接的版本,不会因为有没有一个CoClass编译器可以实际引用.它必须动态地完成它.
我可能会尝试使用此信息伪造一个COM接口,看看我是否可以让编译器链接它...
Ras*_*ber 27
只是为Michael的回答添加一点确认:
以下代码编译并运行:
public class Program
{
public class Foo : IFoo
{
}
[Guid("00000000-0000-0000-0000-000000000000")]
[CoClass(typeof(Foo))]
[ComImport]
public interface IFoo
{
}
static void Main(string[] args)
{
IFoo foo = new IFoo();
}
}
Run Code Online (Sandbox Code Playgroud)
你需要它ComImportAttribute和GuidAttribute它的工作.
当你将鼠标悬停在new IFoo():Intellisense上正确掌握信息时,请注意信息:很好!