EKsumic's Blog

let today = new Beginning();

Click the left button to use the catalog.

OR

C#接口(补充)

接上一讲→C#接口

 

Virtual的实现接口成员

▢ 隐式实现的接口成员默认是sealed。

 

▲ 什么是隐式实现的接口成员

public class Parent : IFoo, IBar
    {
        //隐式实现
        public void Do()
        {
            Console.WriteLine("Foo");
        }

        //显式实现
        int IBar.Do()
        {
            Console.WriteLine("Bar");
            return 0;
        }
    }

▢ 如果想要进行重写的话,必须在基类中把成员标记为virtual或者abstract。

public interface IUndoable{void Undo();}

public class TextBox:IUndoable
{
    public virtual void Undo()=>Console.WriteLine("TextBox.Undo");
}

public class RichTextBox:TextBox
{
    public override void Undo()=>Console.WriteLine("RichTextBox.Undo");
}

☆ 其实你不用virtual 、override也能运行,但是子类的这种行为相当于隐藏父类的方法。

 

 

直接重写:

namespace 隐式实现接口成员
{
    public interface IFoo
    {
         void Do();
    }

    public class Parent : IFoo
    {
        public void Do() => Console.WriteLine("Parent");
    }

    public class Child : Parent
    {
        public void Do() => Console.WriteLine("Child");
    }
    class Program
    {
        static void Main(string[] args)
        {
            Child c = new Child();
            c.Do();
            ((Parent)c).Do();
            ((IFoo)c).Do();
            Console.Read();
        }
    }
}

输出:

Child
Parent
Parent

 

 

virtual 、override后重写:

namespace 隐式实现接口成员2
{
    public interface IFoo
    {
        void Do();
    }

    public class Parent : IFoo
    {
        public virtual void Do() => Console.WriteLine("Parent");
    }

    public class Child : Parent
    {
        public override void Do() => Console.WriteLine("Child");
    }
    class Program
    {
        static void Main(string[] args)
        {
            Child c = new Child();
            c.Do();
            ((Parent)c).Do();
            ((IFoo)c).Do();
            Console.Read();
        }
    }
}

输出:

Child
Child
Child

 

★ 你可以认为例1是三级架构,当你写了virtual 、override,是二级架构

real

 

显式实现的接口不可以被标记为virtual,也不可以通过寻常的方式来重写,但是可以对其进行重新实现。

重新实现是指 → 子类:父类,接口

重新实现适用于重写显式实现的接口成员:

public interface IUndoable{void Undo();}

public class TextBox:IUndoable
{
    void IUndoable.Undo()=>Console.WriteLine("TextBox.Undo");
}

public class RichTextBox:TextBox,IUndoable
{
    protected override void Undo()=>Console.WriteLine("RichTextBox.Undo");
}

具体实例:

namespace 显式实现接口成员
{
    public interface IFoo
    {
        void Do();
    }

    public class Parent : IFoo
    {
        void IFoo.Do() => Console.WriteLine("Parent");
    }

    public class Child : Parent, IFoo
    {
        public void Do() => Console.WriteLine("Child");
    }
    class Program
    {
        static void Main(string[] args)
        {
            Child c = new Child();
            c.Do();
            ((IFoo)c).Do();
            Console.Read();
        }
    }
}

输出:

Child

Child

 

 

重新实现接口的替代方案


即使是显式实现的接口,接口的重新实现也可能有一些问题:
▢ 子类无法调用基类的方法
▢ 基类的开发人员没有预见到方法会被重新实现,并且可能不允许潜在的后果

设计一个无需重新实现的基类:
▢ 隐式实现成员的时候,按需标记virtual
▢ 显式实现成员的时候,可以这样做:

public class TextBox:IUndoable
{
    void IUndoable.Undo()=>Undo();
    protected virtual void Undo()=>Console.WriteLine("TextBox.Undo");
}

public class RichTextBox:TextBox
{
    protected override void Undo()=>Console.WriteLine("RichTextBox.Undo");
}

 

这种类似裹脚布的做法,都是为了满足部分奇葩需求搞的。

 

没事别去重新实现别人定义的显式实现方法,

 

因为,定义成显式就是为了 不要随便用它。

 


接口与装箱

▢ 把struct转化为接口会导致装箱
▢ 调用struct上隐式实现的成员不会导致装箱

interface I{void Foo();}
struct S:I{public void Foo(){}}
...
S s=new S();
s.Foo();     //No Boxing

I i=s;    // Box occurs when casting to interface
i.Foo();

 

This article was last edited at 2020-03-16 23:24:08

* *