关于C#接口的种种

(*) 接口也可以继承接口,但子接口不提供父接口方法的实现

 

(*) 当一个类同时继承父类又实现接口,要把接口放在最后面,如class xxx : ParentClass, ISomeInterface

 

(*) 当同时实现的多个接口中出现同名方法

除了解决同名方法冲突,此段代码同时展示了3种使用接口的方式:

public   interface  IDraw
{
    
void  Draw();
}

public   interface  IDraw3D
{
    
void  Draw();
}

public   class  Image : IDraw, IDraw3D
{
    
// public void IDraw.Draw()   Error! 加任何访问修饰符都会有编译错误
     void  IDraw.Draw()  //  用指定接口名来解决命名冲突,记住这样不能加访问修饰符
    {
        Console.WriteLine(
" IDraw " );
    }

    
void  IDraw3D.Draw() 
    {
        Console.WriteLine(
" IDraw 3D " );
    }
}

class  Program
{
    
static   void  Main( string [] args)
    {
        Image image 
=   new  Image();

        
//  方法1
         try
        {
            ((IDraw)image).Draw();
        }
        
catch  (InvalidCastException ex)
        {
            Console.WriteLine(
" Wrong type! " );
        }

        
//  方法2
        IDraw draw  =  image  as  IDraw;
        
if  (draw  !=   null )
        {
            draw.Draw();
        }
        
else
        {
            Console.WriteLine(
" Wrong type! " );
        }

        
//  方法3
         if  (image  is  IDraw)
        {
            draw.Draw();
        }
        
else
        {
            Console.WriteLine(
" Wrong type! " );
        }
    }
}

 

(*) 自动生成代码

实现接口的类要写不少代码,而且还经常会碰到上面说的语法问题,所以VS提供了一种自动生成代码的方式。

当写好一个类的框架后,如下:

public class Image : IDraw, IDraw3D

{}

把鼠标放在接口上,然后就不说了吧。注意有两种,一种是普通的implement,另一种是explicit implement(即带接口名且没有访问修饰符的)。

 

 

(*) 常用接口

(*) IEnumerable
实现IEnumerable接口才能使用foreach,实现IEnumerable接口只需要实现一个GetEnumerator方法。
public interface IEnumable
{
    IEnumerator GetEnumerator();
}
注意到GetEnumerator返回一个IEnumerator,这又是一个接口,定义如下:

public   interface  IEnumerator
{
    
bool  MoveNext();  //  还有下一个则前往下一个并返回ture,否则返回false
     object  Current {  get ; }  //  readonly property,这也是为什么foreach不能改写元素
     void  Reset();   //  不同于C++的迭代器,reset之后不是指向第一个元素,而是第一个元素之前
}

在实际应用中往往用不着去实现所有这些,因为很多集合例如Array已经实现好了这些接口,
比较常见的一种用法:
IEnumerable在命名空间System.Collections里。

using  System.Collections;


class  MyItem
{
    
//
}

class  MyList : IEnumerable
{
    
private  MyItem[] myArray;

    
#region  IEnumerable Members

    
public  IEnumerator GetEnumerator()
    {
        
return  myArray.GetEnumerator();
    }

    
#endregion
}

 

也可用yield来实现IEnumerable接口。看代码:

public   class  DaysOfWeek : IEnumerable
{
    
string [] m_Days  =  {  " Sun " " Mon " " Tue " " Wed " " Thr " " Fri " " Sat "  };

    
#region  IEnumerable Members
    
    
public  IEnumerator GetEnumerator()
    {
        
yield   return  m_Days[ 2 ];
        
yield   return  m_Days[ 4 ];
        
yield   return  m_Days[ 6 ];
        
yield   break ;
    }

    
#endregion
}

class  TestDaysOfTheWeek
{
    
static   void  Main()
    {            
        DaysOfWeek week 
=   new  DaysOfWeek();
        
        
foreach  ( string  day  in  week)
        {
            System.Console.WriteLine(day);
        }
     
        IEnumerator myEnumerator 
=  week.GetEnumerator();
        
while  (myEnumerator.MoveNext()  ==   true )
        {
            System.Console.WriteLine(myEnumerator.Current);
        }
    }
}

 

yield是很了不起的,它像是一个状态机,记录着迭代器中当前的位置。下面这段关于yield的话是我从别处抄来的,写的似乎很有道理:
1。代码很简洁。其实这里多了一个yield return 语句,由于yield return并不对应多余的il指令。所以编译器就会在编译的时候,生成一个实现Ienumator接口的类.并且自动维护该类的状态.比如movenext,

2. 使用yield return 很容易实现递归调用中的迭代器. 如果以上的问题,不使用yield return的话,可想而知.要么你先把所有的结果暂时放到一个对象集合中. 可是这样就以为着在迭代之前一定要计算号. 要么可能你的movenext 就相当的复杂了. .NET 编译生成的代码其实利用了state machine. 代码量也很大.

类似迭代的调用,比如二叉树遍历 用yield return 就很方便了.另外还有常说的pipeline模式也很方便了.

可是yield return 还是有一些缺陷.

比如:如果有一个参数是ref 或者 out, 那这个state machine就很难去维护状态了. 事实上,yield不支持方法带有ref或者out参数的情况. 还有很多它也不支持,例如unsafe,catch等等,详见MSDN.

 

(*) ICloneable
只要实现一个Clone方法就行了。这个有点儿像C++中自定义的拷贝构造函数,例如我们不想让多个引用同时指向一个资源,就可以在拷贝构造函数中新申请一个资源。也就是所谓的深拷贝。
需要稍微注意的一点:Clone的signature是
object Clone();
所以在调用Clone的时候经常伴随转型操作,例如:Point p2 = (Point)p1.Clone();

一个深拷贝的例子:
public object Clone()
{
 Point newPoint = (Point)this.MemberwiseClone(); // MemberwiseClone是object都有的protected方法
 // TODO: 其他需要深拷贝的操作
}

(*) IComparable
和C标准库里的binary_search的钩子函数一个道理。
public interface IComparable
{
    int CompareTo(object obj); // this在obj前面(也可以说this比obj小)返回负数,this在obj后面返回正数,相等返回0
}
实现了CompareTo方法之后,就可以用Array的静态方法Array.Sort来排序了。看下面代码:

     class  Student : IComparable
    {
        
string  name;
        
int  score;

        
public  Student( string  name,  int  score) 
        {
            
this .name  =  name;
            
this .score  =  score;
        }

        
public   override   string  ToString()
        {
            
return  String.Format( " {0} {1} " , name, score);
        }
        
        
#region  IComparable Members

        
public   int  CompareTo( object  obj)
        {
            Student temp 
=  (Student)obj;
            
//  谁的分高谁在前
             if  ( this .score  >  temp.score) 
            {
                
return   - 1 ;
            }
            
else   if  ( this .score  <  temp.score)
            {
                
return   1 ;
            }
            
else
            {
                
return   0 ;
            }
        }

        
#endregion
    }

    
class  Program
    {
        
static   void  Main()
        {
            Student stu1 
=   new  Student( " Bill " 75 );
            Student stu2 
=   new  Student( " Steve " 85 );
            
// Console.WriteLine(stu1 > stu2);  实现了CompareTo函数也不能直接用>和<来比较
            Console.WriteLine(stu1.CompareTo(stu2));  //  若stu1比stu2靠后,则返回正数

            Student[] group 
=   new  Student[ 2 ];
            group[
0 =  stu1;
            group[
1 =  stu2;
            Array.Sort(group);
            
foreach  (Student stu  in  group)
            {
                Console.WriteLine(stu);
            }
        }
    }

Array.Sort还提供了重载,即允许把排序准则当参数传入。

interface IComparer
{
    int Compare(object o1, object o2);
}

//实现IComparer接口的类
public class NameComparer : IComparer
{
    // 按名字排序
}

//调用
Array.Sort(group, new NameComparer);

 

转载于:https://www.cnblogs.com/dc10101/archive/2009/03/17/1414744.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值