学习C#这么多年,最不好理解的对于我来说就是委托跟接口了.最近认真的琢磨了下.加上网上的实例,略有所懂
通常我们的业务交给暴露给外部使用的时候,一般情况会采用接口的方式,但有时候,我们也会也会为对外暴露的业务接口提供默认的操作方法。
很多时候,我们在别人提供的接口的默认方法时候,很难找到该接口的对应该方法(比较规范的编程方式还好找,如果是杂草式的编程方式的话,估计找半天都找不到)
由此,我们对该问题展开讨论解决。
我们都知道“接口是不能实例化接口”的。
如(错误):
public interface IErrorFace
{
void Error();
}
//错误的使用接口方式:
IErrorFace ef = new IErrorFace();
但我们可以通过实现接口来完成这一个功能。
如(正确):
public interface IErrorFace
{
void Error();
}
public class ErrorFace:IErrorFace
{
public void Error()
{
//TODO
}
}
//使用接口:
IErrorFace ief = new ErrorFace();
ief.Error();//已在ErrorFace实现接口IErrorFace的方法
但是我们采用了上面的正确方法,最终我们还是需要很努力的找出该接口对应的默认方法,那有没有一种方法可以按上面错误的方式使用,又能按上面正确方式执行里面的方法呢?
下面我们请出几个特性来解决这一难题:ComImport,Guid,CoClass,这些特性位于:using System.Runtime.InteropServices;命名空间中
我们将以上两种方式合并得到:
[ComImport]
[Guid("12341234-1234-1234-1234-123412341234")]
[CoClass(typeof(ErrorFace))]
public interface IErrorFace
{
void Error();
}
public class ErrorFace:IErrorFace
{
public void Error()
{
//TODO
}
}
//使用接口:
IErrorFace ief = new IErrorFace();
ief.Error();
IErrorFace ief1 = new ErrorFace();
ief1.Error();
当然,我们也新写一个对象来继续这个接口:
public class ErrorFaceV1:IErrorFace
{
public void Error()
{
//TODO
}
}
//使用接口:
IErrorFace ief = new ErrorFaceV1();
ief.Error();//在ErrorFace实现接口的方法
但是有一点就是,这种接口的语法糖无法在外部识别其CoClass通过InteropClass编译时,只能通过内部编译别。
如:
public class ErrorFaceV2
{
public void ErrorUse()
{
//TODO
}
}
以上的代码并没有继承IErrorFace接口,但它却可以编写如下(在编译过程中不会报错):
//使用接口:
IErrorFace ief = new ErrorFaceV1();
ErrorFaceV2 v2=(ErrorFaceV2)ief;//该转换在执行过程出错,在编译过程不会出错。
ief.Error();//在ErrorFace实现接口的方法
首先,我们必须明确,接口是一个类。
“接口是一个特殊的类,又是一个特别有意义的类,不是因为它的特殊,而是因为它的意义,叫它接口更合适,但不能忘了,它仍是类。”
“接口是一个只有声明,没有实现的类。”
很多人纠结于接口只是一个标准,是一个契约,而忘记了它的意义。
下面我们来看这样一个问题:
话说有家影视公司选拔偶像派男主角,导演说了,男演员,身高是王道。于是有下面代码:
public class Actor {     private string name;     private int height;       public Actor(string name, int height)     {         this.name = name;         this.height = height;     }     public string Name     {         get { return this.name; }     }     public int Height     {         get { return this.height; }     }           public int CompareTo(object obj)     {         return this.height - ((Actor)obj).height;     }       public string GetName()     {         return this.name;     } } | 
这个类,除了可以存放男演员的基本信息,还定义了一个函数publicint CompareTo(object obj),因为,我们要比较男演员的身高,用身高判断哪个演员更好。
有了这个类,后面,你可以比较轻松地编写代码,判断是刘德华更优秀,还是潘长江更优秀了,这个代码,我这里就略过去了….
(儿童不宜,此处省略1000行)……………….
现在的问题是,明天又要选拨女演员了,导演说了,女演员,苗条是王道。女演员的这个类,你肯定是要做的,只是….
只是,我刚才略过去的,让你编写的代码,你是不是还要再重新编写呢????
这等于又重新编写了一个程序。
这时,我们就想到了接口,我们来接着看代码吧:
我先做一个接口:
using System;   namespace WestGarden.IDAL {     public interface ISelectPlayer     {         string GetName();           int CompareTo(object obj);     } } | 
这个接口,定义了两个函数,一个,当然是要进行比较,标准由你定,你说是导演定的,那更好,不用你费脑子了。
我们把刚才做的男演员的类,按照这个接口的标准来实现,也就是继承这个接口:
using System;   using WestGarden.IDAL;   namespace WestGarden.DAL {     public class Actor:ISelectPlayer     {         private string name;         private int height;           public Actor(string name, int height)         {             this.name = name;             this.height = height;         }         public string Name         {             get { return this.name; }         }         public int Height         {             get { return this.height; }         }                  public int CompareTo(object obj)         {             return this.height - ((Actor)obj).height;         }           public string GetName()         {             return this.name;         }     } } | 
顺手,把女演员的类也做了吧:
using System;   using WestGarden.IDAL;   namespace WestGarden.DAL {     public class Actress:ISelectPlayer     {         private string name;         private int weight;                   public Actress(string name, int weight){             this.name = name;             this.weight = weight;         }           public string Name         {             get { return this.name; }         }         public int Weight         {             get { return this.weight; }         }               public int CompareTo(object obj)         {             return ((Actress)obj).weight - this.weight;         }           public string GetName()         {             return this.name;         }     } } | 
这时,我们在应用层这样编写代码:
using System;   using WestGarden.IDAL; using WestGarden.DAL;   namespace WestGarden.Web {     public partial class Select : System.Web.UI.Page     {         protected void Page_Load(object sender, EventArgs e)         {             Actor actor1 = new Actor("潘长江", 150);             Actor actor2 = new Actor("刘德华", 180);               Actress actress1 = new Actress("巩俐", 120);             Actress actress2 = new Actress("周迅", 80);               Response.Write("最佳男演员是:"+WhoIsBetter(actor1, actor2)+"</br>");             Response.Write("最佳女演员是:"+WhoIsBetter(actress1, actress2)+"</br>");         }           //这里就象一个USB口一样工作着,无论你插上的是男演员、女演员...,只要它继承的是ISelectPlayer接口。         public string WhoIsBetter(ISelectPlayer a, ISelectPlayer b)         {             if (a.CompareTo(b) > 0)                 return a.GetName();             else                return b.GetName();         }     } } | 
注意:
我们做的这个函数,publicvoid WhoIsBetter(ISelectPlayer a,ISelectPlayer b)
这个函数,形参是ISelectPlayer,是接口,我认为,接口的意义,就在这里。
你实现接口的类是男演员也好,女演员也好,男主角也好、女主角也好、男配角也好、女配角也好、男群众演员也好、女群众演员也好,只要你继承的是我这个ISelectPlayer,或者,你习惯于说,遵守了我这个接口的标准、或者契约,我这段代码,都不需要改变!!
这和那个比方是一样的,不管你插在USB接口的是U盘,还是移动硬盘,还是什么mp3,还是mp4,还是你新发明的什么东西,只要你能插在我的USB口上,我主机都不需要做任何改变,直接在上面读取或者写入数据。
这个,是硬件接口的意义所在,也是我们这个ISelectPlayer类的意义所在,因为它有了这个伟大的意义,才把它改叫为接口的,因为,它象USB接口一样工作着……
                    
                
                
            
        
浙公网安备 33010602011771号