博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

C#接口深度剖析(子类重新实现)

Posted on 2010-09-28 17:30  qianyz  阅读(3355)  评论(1编辑  收藏  举报

在园子中看到好多人只能分析多态的内存模型,却对接口的内存模型无法探知,其实多态的实现机制很简单,接口的也不难,下面就分析一个例子

interface IFather
    {
        void X();
        void Y();
        void Play();
        void Clear();
    }
    class B : IFather
    {
        public void X()
        {
            Console.WriteLine("B::X()");
        }
        public void Y()
        {
            Console.WriteLine("B::Y()");
        }
        public void Play()
        {
            Console.WriteLine("B::Play()");
        }
        public void Clear()
        {
            Console.WriteLine("B::Clear()");
        }
    }
    class C : B, IFather
    {
        public new void Play()
        {//该方法虽然隐藏了基类中的方法,并且是虚的
            Console.WriteLine("C::Play()");
        }
        public new void Clear()
        {//该方法虽然隐藏了基类中的方法,并且是虚的
            Console.WriteLine("C::Clear()");
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            C c = new C();
            c.X();//B::x()
            c.Y();//B::y()
            c.Play();//C::play()
            c.Clear();//C::clear()
            IFather f = c;
            f.X();//B::x()
            f.Y();//B::y()
            f.Play();//C::play()
            f.Clear();//C::clear()
            Console.Read();
        }
    }

 

注意:如果一个类实现一个接口,而这个接口已经在这个类的基类中已经实现过了,那么这时候,虚方法表中会不会新开槽呢?1如果父类中实现接口的方法是虚的,这时很明显,在子类中实现时如果是override就会公用对应的槽,如果是virtual new 会新开一个槽,如果是new 那么就不好说了,因为会先匹配本类中的方法,所以最后也被虚化,是会新开一个槽的。2 如果在父类中是public非virtual的,那么在父类中对应的几个方法是被虚拟化的(public virtual seleaed),在子类中是不能override的,只能new了(因为被虚化密封了),如果是virtual new 这是会新开槽的,也会匹配到新的方法上来,如果是new 就要根据匹配顺序看是否虚化,如果虚拟化了就也要新开槽了,(注意:如果是公有非静态的,会虚化,就成密封的了,这时是不能override的,只能用new来隐藏一下了)。对本例子分析:编译器首先看是显式实现,那么就重新匹配接口中的方法。这时根据接口的匹配原则先找本类显式实现,没有找到,然后找本类虚方法也没有找到,然后找本类公有非静态方法,找到了play(),clear(),然后将其虚化,再在直接父类中找,先找虚方法,然后找到了x(),y(),即实现了(解释:在父类中实现的接口要在子类中重新实现,就要显示表明接口的继承,这是在编译的时候编译器看到了接口的重新实现就会重新匹配接口中的方法,如果是隐式实现接口,编译器一看是隐式的,就什么也不考虑,直接继承基类中原有的匹配)