在 C# 中,接口(Interface)是一种定义了一组相关方法、属性和事件的合同(contract),用于实现类来遵循。接口定义了类应该具有的成员,但不提供实现。类可以实现一个或多个接口,并提供相应的实现代码。
通过实现接口,类可以遵循接口定义的合同,并提供特定的行为。这使得类可以以一种统一的方式与其他类和组件进行交互,实现了接口的多态性(polymorphism)。
接口还可以用于实现接口间的继承关系。一个接口可以继承自另一个接口,这样实现该派生接口的类需要同时满足两个接口的要求。
接口在 C# 中常用于定义插件架构、实现依赖注入、编写可测试的代码等场景。它们提供了一种灵活而强大的方式来定义和组织代码,使得代码更加可扩展、可维护和可重用。
1、接口的定义
在 C# 中,可以使用 interface
关键字来定义接口。接口定义了一组方法、属性、事件或索引器的规范,而不提供它们的实际实现。以下是定义接口的语法:
public interface InterfaceName
{
// 方法、属性、事件和索引器的声明
}
接口名称通常以大写字母 “I” 开头,表示接口(Interface)的含义,然后跟随具体的接口名称。接口定义应该放在命名空间内部或类内部,以根据使用情况进行适当的封装。
接口可以包含多个成员,包括方法、属性、事件和索引器。这些成员只有声明,没有实际的实现。例如,以下是一个包含方法和属性的接口示例:
public interface IExampleInterface
{
void Method1();
int Property1 { get; set; }
}
在上述示例中,IExampleInterface
接口定义了一个无返回值的方法 Method1
和一个读写属性 Property1
。
接口成员可以有各种访问修饰符(public、private、internal、protected),但接口自身的成员默认为公共访问修饰符(public)。接口成员不允许有访问修饰符 private
或 protected
,因为接口成员必须为实现接口的类可见。
接口还可以继承其他接口,通过使用冒号 (:
) 来指定基接口。例如:
public interface IChildInterface : IParentInterface
{
// 子接口成员声明
}
在上述示例中,IChildInterface
接口继承了 IParentInterface
接口。
类可以实现一个或多个接口,并通过提供相应的实现来满足接口的合同。类通过使用 class
关键字声明,并使用 : InterfaceName
来表示实现的接口。例如:
public class ExampleClass : IExampleInterface
{
public void Method1()
{
// 方法实现
}
public int Property1 { get; set; }
}
在上述示例中,ExampleClass
类实现了 IExampleInterface
接口,并提供了 Method1
方法和 Property1
属性的具体实现。
通过接口,我们可以定义一组规范,以使类具备特定的行为,并实现接口的多态性。这样,我们可以使用接口引用来操作不同的类实例,以达到代码的灵活性和扩展性。
2、接口的实现
[类]在 C# 中,要实现接口,需要使用类或结构来提供接口定义的成员的具体实现。一个类可以实现一个或多个接口,并提供每个接口成员的具体实现。
以下是一个示例,展示了如何在类中实现接口:
// 定义一个接口
public interface IExampleInterface
{
void Method1();
int Property1 { get; set; }
}
// 实现接口的类
public class ExampleClass : IExampleInterface
{
public void Method1()
{
Console.WriteLine("Method1 implementation");
}
public int Property1 { get; set; }
}
在上述示例中,ExampleClass
类实现了 IExampleInterface
接口。它提供了 Method1
方法和 Property1
属性的具体实现。
接口的方法实现由实现类根据自身的逻辑来编写。在 Method1
方法的实现中,我们打印了一条消息。属性的实现可以是简单的自动属性(auto-implemented property),如上述示例中的 Property1
。
接口的成员在实现类中应该使用相同的名称和签名。当一个类实现一个接口时,它必须提供接口中声明的所有成员的实现。
接口还可以继承其他接口,通过使用冒号 (:
) 来指定基接口。例如:
public interface IChildInterface : IParentInterface
{
// 子接口成员声明
}
public interface IParentInterface
{
void ParentMethod();
}
public class ExampleClass : IChildInterface
{
public void ParentMethod()
{
Console.WriteLine("ParentMethod implementation");
}
// IChildInterface 成员的实现
// ...
}
在上述示例中,IChildInterface
接口继承了 IParentInterface
接口,并且 ExampleClass
类实现了 IChildInterface
接口。它提供了 ParentMethod
方法的具体实现,并可以根据需要提供 IChildInterface
的其他成员的实现。
[结构体]
public interface IExampleInterface
{
void Method1();
int Property1 { get; set; }
}
public struct ExampleStruct : IExampleInterface
{
public void Method1()
{
Console.WriteLine("Method1 implementation");
}
public int Property1 { get; set; }
}
在上述示例中,我们定义了一个接口 IExampleInterface
,其中包含一个方法 Method1
和一个属性 Property1
。然后,我们创建了一个结构体 ExampleStruct
,并通过 : IExampleInterface
指定了它实现了 IExampleInterface
接口。
结构体中的接口实现与类中的接口实现类似。我们提供了 Method1
方法的具体实现,并定义了一个自动属性 Property1
。
需要注意的是,在结构体中实现接口时,结构体是值类型,而接口是引用类型。因此,在结构体中实现接口时,实现的接口成员是在结构体的副本上调用的,而不是对原始结构体的引用。
使用结构体实现接口时,可以像操作类实例一样使用结构体实例,并通过接口类型的引用来调用接口的成员。例如:
ExampleStruct example = new ExampleStruct();
example.Method1();
example.Property1 = 10;
在上述示例中,我们创建了一个 ExampleStruct
结构体的实例,并使用它调用了接口的方法和访问了接口的属性。
结构体实现接口可以用于一些特定的场景,如需要值类型语义、节省内存或需要在栈上分配的情况。但需要注意的是,结构体在复杂逻辑和大量数据存储方面可能不如类灵活和高效。因此,在选择结构体还是类来实现接口时,应根据具体情况和需求做出选择。
*{当我们声明对象是结构体类型时,对象是值类型,对象在栈中创建*
*当我们声明对象是接口类型时,对象是引用类型,对象在堆中创建}*(调用时)
通过实现接口,类可以遵循接口定义的合同,并提供特定的行为。这使得类可以以一种统一的方式与其他类和组件进行交互,实现了接口的多态性。
3、接口的调用
在 C# 中,可以通过接口类型的引用来调用接口的成员。接口类型的引用可以引用实现了该接口的类的实例。这样做可以实现对不同类的实例进行统一的操作。
以下是一个示例,展示了如何使用接口类型的引用来调用接口的成员:
public interface IExampleInterface
{
void Method1();
int Property1 { get; set; }
}
public class ExampleClass : IExampleInterface
{
public void Method1()
{
Console.WriteLine("Method1 implementation");
}
public int Property1 { get; set; }
}
public class Program
{
public static void Main()
{
IExampleInterface example = new ExampleClass(); // 实例化 ExampleClass,并将其赋值给接口类型的引用
example.Method1(); // 调用接口的方法
example.Property1 = 10; // 访问接口的属性
}
}
在上述示例中,我们定义了 IExampleInterface
接口和 ExampleClass
类,ExampleClass
类实现了 IExampleInterface
接口。然后,在 Program
类的 Main
方法中,我们实例化 ExampleClass
,并将其赋值给接口类型的引用 example
。通过这样做,我们可以使用 example
引用来调用接口的方法和访问接口的属性。
注意,通过接口类型的引用调用接口的成员时,实际执行的是实现类中的具体实现。这样可以实现对实现了同一接口的不同类的实例进行统一的操作,提高代码的灵活性和可扩展性。
在实际开发中,接口的调用经常用于实现依赖注入、面向接口编程等场景。通过定义和使用接口,我们可以实现松耦合的设计,提高代码的可测试性和可维护性。
接口和抽象类的具体区别
在选择接口或抽象类时,应根据具体的需求和设计目标来确定。如果需要定义一组方法签名,以实现多态性和契约编程,或者需要支持多重继承,那么接口是一个好的选择。如果需要定义一个通用的抽象概念,并提供一些默认的实现,或者需要在继承层次结构中共享代码和状态,那么抽象类是一个更合适的选择。
需要注意的是,C# 中的类可以同时实现接口和继承抽象类,以充分利用它们的特性。这种组合使用可以提供更灵活和可扩展的设计。
一、接口注意的几点:
1、接口方法不能用public abstract等修饰。接口内不能有字段变量,构造函数。
2、接口内可以定义属性(有get和set的方法)。如string color { get ; set ; }这种。
3、实现接口时,必须和接口的格式一致。
4、必须实现接口的所有方法。
二、接口的定义是指定一组函数成员而不实现成员的引用类型,其它类型和接口可以继承接口。接口主要有以下特点:
1、通过接口可以实现多重继承,C# 接口的成员不能有 public、protected、internal、private 等修饰符。原因很简单,接口里面的方法都需要由外面接口实现去实现方法体,那么其修饰符必然是 public。C# 接口中的成员默认是 public 的。
2、接口成员不能有 new、static、abstract、override、virtual 修饰符。有一点要注意,当一个接口实现一个接口,这2个接口中有相同的方法时,可用 new 关键字隐藏父接口中的方法。
3、接口中只包含成员的签名,接口没有构造函数,所以不能直接使用 new 对接口进行实例化。接口中只能包含方法、属性、事件和索引的组合。接口一旦被实现,实现类必须实现接口中的所有成员,除非实现类本身是抽象类。
4、C# 的类是单继承,接口是解决 C# 里面类可以同时继承多个基类的问题。