随笔 - 90  文章 - 0 评论 - 94 阅读 - 60万

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

 

(*) 当一个类同时继承父类又实现接口,要把接口放在最后面,如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);

 

posted on   MainTao  阅读(2428)  评论(2编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示