1.接口类型
接口是一组抽象成员的命名集合。
public interface IDbConnection : IDisposable
{
IDbTransaction BeginTransaction();
IDbTransaction BeginTransaction(IsolationLevel il);
void ChangeDatabase(string databaseName);
void Close();
IDbCommand CreateCommand();
void Open();
string ConnectionString{get;set;}
int ConnectionTimeout{get;}
string Database{get;}
ConnectionState State{get;}
}
接口成员总是抽象的, 每一个连接对象完全可以以自己的方式来实现这些方法。
接口只能包含抽象成员。
接口可以被任何层次结构,任何命名空间或任何程序集中的任何类或结构来实现。
可通过接口类型,来把实现了特定接口的类型当成多态处理。
public interface ICloneable
{
object Clone();
}
class MyApp
{
static void Main()
{
string mystr = "Hello";
OperatingSystem unixOs = new OperatingSystem(PlatformID.Unix, new Version());
System.Data.SqlClient.SqlConnection sqlCnn = new System.Data.SqlClient.SqlConnection();
CloneMe(myStr);
CloneMe(unixOs);
CloneMe(sqlCnn);
}
private static void CloneMe(ICloneable c)
{
object theClone = c.Clone();// 将指向c的动态类型,对应版本的ICloneable::Clone
}
}
2.定义自定义接口
接口不指定基类,接口可以指定基接口。
接口的成员也不指定访问修饰符【接口成员是隐式公共和抽象的】
接口是纯粹的协议,不会定义实现。
接口不能有字段,构造函数,不能提供函数实现。
接口中可以定义属性。也可以包含事件以及索引器。
接口本身仅仅是抽象成员的集合,只有被具体的类或结构实现时,才有其意义。
3.实现接口
public class Pencil : IPointy
{...}
public class SwitchBlade : object, IPointy
{...}
public class Fork : Utensil, IPointy
{...}
public struct Arrow : ICloneable, IPointy
{...}
实现接口是一个“要么全要要么全不要”的命题。
public interface IPointy
{
byte Points{get;}
}
class Triangle : Shape, IPointy
{
...
public byte Points
{
get{return 3;}
}
}
class Hexagon : Shape, IPointy
{
...
public byte Points
{
get{return 6;}
}
}
4.在对象级别调用接口成员
如何动态判断一个类型支持哪些接口?
在运行时判断一个类型是否支持一个指定接口的方式
4.1.使用显式强制转换。如类型不支持被请求的接口,将收到一个无效转换异常【InvalidCastException】。
4.2.as
static void Main()
{
Hexagon hex2 = new Hexagon("Peter");
// 若Hexagon实现了IPointy,则返回转换后的IPointy
// 若没实现,返回null
IPointy itfPt2 = hex2 as IPointy;
if(itfPts != null)
....
}
4.3.is
static void Main()
{
Hexagon hex2 = new Hexagon("Peter");
// 若Hexagon实现了IPointy,则返回true
// 若没实现,返回false
if(hex2 is IPointy)
// hex2.Points
}
5.接口做参数
接口可以做参数, 任何实现了此接口的类型实例,均可以作为实参传递。
在函数内,对接口对象执行成员调用时,将调用接口对象动态类型对应的实现版本。
6.接口作为返回值
static IPointy FindFirstPointyShape(Shape[] shapes)
{
foreach(Shape s in shapes)
{
if(s is IPointy)
return s as IPointy;
}
return null;
}
7.接口类型数组
static void Main()
{
IPointy[] myPointObjects =
{
new Hexagon(),
new Knife(),
new Triangle(),
new Fork(),
new PitchFork()
};
foreach(IPointy i in myPointyObjects)
{
Console.WriteLine("Object has {0} points", i.Points);
}
}
8.显式接口实现
一个类或接口可以实现多个接口,多个接口可能包含同名且参数列表一致的成员。这时要处理冲突。
public interface IDrawToForm
{
void Draw();
}
public interface IDrawToMemory
{
void Draw();
}
public interface IDrawToPrinter
{
void Draw();
}
class Octagon : IDrawToForm, IDrawToMemory, IDrawToPrinter
{
// IDrawToForm, IDrawToMemory, IDrawToPrinter接口共享同一实现
public void Draw()
{
Console.WriteLine("Drawing the Octagon...");
}
}
class OctagonEx : IDrawToForm, IDrawToMemory, IDrawToPrinter
{
// 提供独立实现。显式实现的成员是自动私有的,不允许指定访问修饰符。
void IDrawToForm.Draw()
{...}
void IDrawToMemory.Draw()
{...}
void IDrawToPrinter.Draw()
{...}
}
class MyApp
{
OctagonEx oct = new OctagonEx();
// 对于在类中提供接口显示实现的类型,接口中显示实现的成员是私有的。
// 要通过此类型访问接口成员的唯一方式是,先把类类型强制转换为接口类型,然后在再执行接口成员访问。
IDrawToForm itfForm = (IDrawToForm)oct;
itfForm.Draw();
}
#.NET基础类库中包含的许多预定义接口
1.IEnumerable,IEnumerator
public interface IEnumerable
{
IEnumerator GetEnumerator();
}
public interface IEnumerator
{
bool MoveNext();
object Current{get;}
void Reset();
}
使用示例:
using System.Collections;
public class Garage : IEnumerable
{
private Car[] carArray = new Car[4];
public Garage()
{
carArray[0] = new Car("FeeFee", 200, 0);
carArray[1] = new Car("Clunker", 80, 0);
carArray[2] = new Car("Zippy", 30, 0);
carArray[3] = new Car("Fred", 30, 0);
}
public IEnumerator GetEnumerator()
{
return carArray.GetEnumerator();
}
}
// 2,3 yield相关并不清楚
2.用yield关键字构建迭代器方法
public class Garage : IEnumerable
{
private Car[] carArray = new Car[4];
public IEnumerator GetEnumerator()
{
foreach(Car c in carArray)
{
// 达到yield return后,当前位置被存储下来。下次调用迭代器时会从这个位置开始执行
yield return c;
}
}
}
3.构建命名迭代器
public IEnumerable GetTheCars(bool ReturnReversed)
{
if(ReturnReversed)
{
for(int i = carArray.Length; i != 0; i--)
{
yield return carArray[i - 1];
}
}
else
{
foreach(Car c in carArray)
{
yield return c;
}
}
}
static void Main()
{
Garage carLot = new Garage();
foreach(Car c in carLot)
{
Console.WriteLine("{0} is going {1} MPH", c.PetName, c.CurrentSpeed);
}
foreach(Car c in carLot.GetTheCars(true))
{
Console.WriteLine("{0} is going {1} MPH", c.PetName, c.CurrentSpeed);
}
Console.ReadLine();
}
2.ICloneable
public interface ICloneable
{
object Clone();
}
public class Point
{
public int X{get; set;}
public int Y{get; set;}
public Point(int xPos, int yPos)
{
X = xPos;
Y = yPos;
}
public Point(){}
public override string ToString()
{
return string.Format("X={0}; Y={1}", X, Y);
}
public object Clone()
{
return new Point(this.X, this.Y);
}
//
public object Clone()
{
// 重新在堆上分配一个类的对象,并对对象的成员变量逐个进行值拷贝。对引用类型成员变量,拷贝后新对象中引用和原对象中引用指向同一个堆上对象。
return this.MemberwiseClone();
}
}
static void Main(string[] args)
{
Point p3 = new Point(100, 100);
Point p4 = (Point)p3.Clone();
// p4.X的改变不影响p3.X
p4.X = 0;
}
更复杂的克隆示例
public class PointDescription
{
public string PetName{get; set;}
public Guid PointID{get; set;}
public PointDescription()
{
PetName = "No-name";
PointID = Guid.NewGuid();
}
}
public class Point : ICloneable
{
public int X{get; set;}
public int Y{get; set;}
public PointDescription desc = new PointDescription();
public Point()
{}
public override string ToString()
{
return string.Format("X={0}, Y={1}, Name={2}, nID={3}\n", X,Y,desc.PetName, desc.PointID);
}
public object Clone()
{
// 分配对象,并逐个按值对对象成员进行复制。
Point newPoint = (Point)this.MemberwiseClone();
PointDescription currentDesc = new PointDescription();
currentDesc.PetName = this.desc.PetName;
newPoint.desc = currentDesc;
return newPoint;
}
}
3.IComparable
public interface IComparable
{
int CompareTo(object o);
}
public class Car : IComparable
{
...
// < 0,A < B
// =,A = B
// >, A > B
int IComparable.CompareTo(object obj)
{
Car temp = obj as Car;
if(temp != null)
{
if(this.CarID > temp.CarID)
return 1;
if(this.CarID < temp.CarID)
return -1;
else
return 0;
}
else
throw new ArgumentException("Parameter is not a Car!");
}
}
4.IComparer
interface IComparer
{
int Compare(object o1, object o2);
}
public class PetNameComparer : IComparer
{
int IComparer.Compare(object o1, object o2)
{
Car t1 = o1 as Car;
Car t2 = o2 as Car;
if(t1 != null && t2 != null)
return String.Compare(t1.PetName, t2.PetName);
else
throw new ArgumentException("Parameter is not a Car!");
}
}
class MyApp
{
public static void Main()
{
Car myAuto[10];
...
Array.Sort(myAutos, new PetNameComparer());
}
}