欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

基于C# 中可以new一个接口?的问题分析

程序员文章站 2023-12-16 18:23:16
如果有人问你,c# 中可以new 一个接口吗?,你会怎么回答? 假设itestinterface 是一个接口,那么这样的代码是否有问题? itestinterfac...

如果有人问你,c# 中可以new 一个接口吗?,你会怎么回答?

假设itestinterface 是一个接口,那么这样的代码是否有问题?

itestinterface testinterface = new itestinterface();

很多书上都会说,当然有问题,接口不能用new ,然后你就认为上面这句语句肯定通不过编译器的编译了。

可是凡事无绝对,c# 竟然允许你这么写,当然你需要加点”料”才行。

vs2005 中新建控制台程序ca2005.添加 microsoft.office.interop.excel 引用

基于C# 中可以new一个接口?的问题分析

基于C# 中可以new一个接口?的问题分析

program 的main函数只有一句话:

基于C# 中可以new一个接口?的问题分析

注意,可以通过编译,看下application的定义:

基于C# 中可以new一个接口?的问题分析

很明显application 是个interface,

这里我要扯一下,经常看到有人说string 是类还是结构什么的,看下string 的定义:

基于C# 中可以new一个接口?的问题分析

 string 是用class 来修饰的,所以string 100% 是类。

还是扯回来吧,application 是个接口,但是我们却可以用new  .为什么

先看下反编译后的代码吧:

基于C# 中可以new一个接口?的问题分析 

可以看到虽然我们写的是new application,但是编译器为我们生成的却是new applicationclass();

难道application 有什么特别的地方?

仔细的同学一眼就看出了application是被这两个特性修饰的:

[coclass(typeof(applicationclass))]

[guid("000208d5-0000-0000-c000-000000000046")]

关于coclass的解释可以看msdn

基于C# 中可以new一个接口?的问题分析 

有些人不喜欢看msdn,而喜欢看博客的一个原因就是msdn太不直白了。

我个人的理解是coclass 就好像concrete class(具体类)

这个特性指示编译器在编译application的时候,使用applicationclass 来实现。

回到上面的最初的问题上:

如何让这段代码通过编译:

itestinterface testinterface = new itestinterface();

通过上面的分析,我们很容易将这个特性来修饰我们的自己的接口:

namespace ca2005

{

    [coclass(typeof(testclass))]

    [guid("6c8bf7fe-1f6b-437e-bcc8-6d2ff04e66b3")]

    public interface itestinterface

    {

        void dosomething();

    }

    [guid("68c7cb18-0dee-4689-845d-741525281c76")]

    public class testclass : itestinterface

    {

        public void dosomething()

        {

            console.writeline("testclass:dosomething");

        }

    }

    class program

    {

        static void main(string[] args)

        {

            microsoft.office.interop.excel.application excelapplication =

                new microsoft.office.interop.excel.application();

            itestinterface testinterface = new itestinterface();

            testinterface.dosomething();

        }

    }

}

编译,结果如下:

基于C# 中可以new一个接口?的问题分析

接口被标记了coclassattribute,而不是comimportattribute.

基于C# 中可以new一个接口?的问题分析

原来想要new 一个接口使用的是编译器对com的优化和支持。

很明显上面的application是一个com对象,所以可以new application

 

itestapplication中添加comimportattribute 特性:

基于C# 中可以new一个接口?的问题分析

再次运行,结果如下:

基于C# 中可以new一个接口?的问题分析

查看下反编译的代码:

基于C# 中可以new一个接口?的问题分析

之所以我对vs2005 用红色字体,是因为如果你用vs2010 创建的程序,那么你会看到不一样的反编译结果:

public static void main()

{

      application application1 = (application) activator.createinstance(type.gettypefromclsid(new guid("00024500-0000-0000-c000-000000000046")));

      itestinterface interface1 = new testclass();

      interface1.dosomething();

      console.readline();

}

这里的type.gettypefromclsid 中的guidapplicationclassguid,也就是coclasstypeguid

[comsourceinterfaces("microsoft.office.interop.excel.appevents")]

    [guid("00024500-0000-0000-c000-000000000046")]

    [typelibtype(2)]

    [classinterface(0)]

    public class applicationclass : _application, application, appevents_event

{

}

这点一定要注意。

楼下有些同学说这有什么意义,下面是我的项目实例,也是这个问题才让我研究了这个问题:

在项目中使用了一种c3读卡器,这种读卡器提供了读卡接口(c3readcard),但是开发环境是2005,所以不能够c3readcard c3=new c3readcard();

这点很奇怪,excel的可以new,但是c3readcard却不可以new,但是通过反射去调用实现类就可以使用c3readcard的接口。

这个问题的意义在于你明白编译器如何去处理new一个接口所生成的代码,也许还有其他的用处,等待你的发现。

上一篇:

下一篇: