在人类世界中,两个或更多人之间的契约约束他们按照契约行事。 同样,接口包括相关功能的声明。 实现接口的实体必须提供声明功能的实现。
在 C# 中,可以使用 interface 关键字定义接口。 接口可以包含方法、属性、索引器和事件的声明。 但是,它不能包含字段、自动实现的属性。
以下接口声明了文件操作的一些基本功能。
interface IFile
{
void ReadFile();
void WriteFile(string text);
}
您不能将访问修饰符应用于接口成员。 默认情况下,所有成员都是公开的。 如果在接口中使用访问修饰符,则 C# 编译器将给出编译时错误"IFile.WriteFile(string)”必须声明主体,因为它未标记为 abstract、extern 或 partial"。(因为它会认为我们尝试做默认实现)
一个类或一个结构可以使用冒号 (:) 实现一个或多个接口。
语法:<类或结构名称>:<接口名称>
例如,以下类隐式实现了 IFile 接口。
interface IFile
{
string ReadFile();
void WriteFile(string text);
string Name { get; }
}
public class MyFile : IFile
{
public string Name
{
get { return "test"; }
}
public string ReadFile()
{
return "hello world";
}
public void WriteFile(string text)
{
Console.WriteLine("写一个文件,这个是假的");
}
}
在上面的例子中,FileInfo 类实现了 IFile 接口。 它用公共访问修饰符定义了 IFile 接口的所有成员。 FileInfo 类还可以包含接口成员以外的成员。 注意 接口成员必须使用 public 修饰符实现; 否则,编译器会给出编译时错误。
您可以创建类的对象并将其分配给接口类型的变量,如下所示。
class Program
{
static void Main(string[] args)
{
IFile file1 = new MyFile();
var file2 = new MyFile();
file1.ReadFile();
file1.WriteFile("content");
file2.ReadFile();
file2.WriteFile("content");
}
}
上面我们看到 MyFile和 IFile都是可以调用ReadFile和WriteFile的。但是显式实现接口的时候会不一样。
可以使用 <InterfaceName>.<MemberName>
显式实现接口。 当类实现多个接口时,显式实现很有用; 因此,它更具可读性并消除了混乱。 如果接口恰好具有相同的方法名称,这也很有用。
interface IFile
{
string ReadFile();
void WriteFile(string text);
}
class MyFile : IFile
{
string IFile.ReadFile()
{
Console.WriteLine("Reading File");
return "abc";
}
void IFile.WriteFile(string text)
{
Console.WriteLine("Writing to file");
}
}
显式实现接口时,只能通过接口类型的实例访问接口成员。
interface IFile
{
string ReadFile();
void WriteFile(string text);
}
public class MyFile : IFile
{
string IFile.ReadFile()
{
Console.WriteLine("Reading File");
return "abc";
}
void IFile.WriteFile(string text)
{
Console.WriteLine("Writing to file");
}
public void Search(string text)
{
Console.WriteLine("Searching in file");
}
}
class Program
{
static void Main(string[] args)
{
IFile file1 = new MyFile();
var file2 = new MyFile();
file1.ReadFile();
file1.WriteFile("content");
//file1.Search("text to be searched")//编译错误,打点也是没有提示的
file2.Search("text to be searched");
//file2.ReadFile(); //编译错误
//file2.WriteFile("content"); //编译错误
}
}
在上面的例子中,file1 对象只能访问 IFile 的成员,file2 只能访问 MyFile 类的成员。 这是显式实现的限制。
C# 中类是没有办法多继承的,但是可以实现多个接口如下。
interface IFile
{
string ReadFile();
void WriteFile(string text);
}
interface IBinaryFile
{
void OpenBinaryFile();
void ReadFile();
}
public class MyFile : IFile, IBinaryFile
{
string IFile.ReadFile()
{
Console.WriteLine("Reading File");
return "abc";
}
void IFile.WriteFile(string text)
{
Console.WriteLine("Writing to file");
}
public void Search(string text)
{
Console.WriteLine("Searching in file");
}
void IBinaryFile.OpenBinaryFile()
{
Console.WriteLine("Opening Binary File");
}
void IBinaryFile.ReadFile()
{
Console.WriteLine("Reading Binary File");
}
}
class Program
{
static void Main(string[] args)
{
IFile file1 = new MyFile();
IBinaryFile file2 = new MyFile();
MyFile file3 = new MyFile();
file1.ReadFile(); //Reading File
//file1.OpenBinaryFile(); //compile-time error
//file1.SearchFile("text to be searched"); //compile-time error
file2.OpenBinaryFile(); // Opening Binary File
file2.ReadFile(); // Reading Binary File
//file2.SearchFile("text to be searched"); //compile-time error
file3.Search("text to be searched"); // Searching in file
//file3.ReadFile(); //compile-time error
//file3.OpenBinaryFile(); //compile-time error
}
}
上面,MyFile 显式地实现了两个接口 IFile 和 IBinaryFile。 建议在实现多个接口时显式实现接口,避免混淆,提高可读性。
很多时候我们会跟据条件来决定要使用哪一个类来做事情,下面代码就展示了这个简单的情况。
interface IFile
{
void Hello();
}
public class MyFile : IFile
{
public void Hello()
{
Console.WriteLine("MyFile");
}
}
public class YourFile : IFile
{
public void Hello()
{
Console.WriteLine("YourFile");
}
}
class Program
{
static void Main(string[] args)
{
IFile file1 = GetFile();
file1.Hello();
}
/// <summary>
/// 跟据条件返回具体的实现类
/// </summary>
/// <returns></returns>
private static IFile GetFile()
{
IFile file1 = null;
if (DateTime.Now.Ticks % 2 == 1) //模拟条件
{
file1 = new MyFile();
}
else
{
file1 = new YourFile();
}
return file1;
}
}
从 C# 8.0 开始,接口成员可以声明主体。 这称为“默认实现”。 具有主体的成员允许接口为不提供重写实现的类和结构提供“默认”实现。 此外,从 C# 8.0 开始,接口可以包括:
interface IFile
{
public void Hello()
{
Console.WriteLine("hello");
}
}
public class MyFile : IFile
{
public void Hello2()
{
((IFile)this).Hello();
}
}
class Program
{
static void Main(string[] args)
{
IFile file1 = new MyFile();
var file2 = new MyFile();
file1.Hello();
// file2.Hello();//编译错误;
file2.Hello2();
}
}