资讯动态

C# 抽象类与接口:相同点、区别与选用建议

发布时间:2026/10/27 1:01:11 来源:尧图企业网站定制
C# 中抽象类与接口在“定义抽象规则”这件事上高度相似很多场景下甚至可以互相替换因此不少开发者在设计时对二者的选择比较随意。实际上两者在继承方式、成员构成、多继承支持和使用场景上都有明显差异。本文先分别用抽象类和接口定义同一组行为再对比它们的相同点与区别最后给出选用建议。一、用抽象类定义 Animal首先以抽象类的方式定义一个公共的抽象类Animalpublic abstract class Animal { public abstract void Run(); public abstract void Eat(); }注意类成员的默认访问级别是private因此抽象成员一定要显式声明为public否则派生类无法重写。二、用接口定义 IAnimal然后使用接口的方式定义IAnimalpublic interface IAnimal { void Run(); void Eat(); }注意虽然 .NET 已不再主张匈牙利命名法但接口名习惯上仍以大写字母I开头用于表明这是一个接口。三、抽象类与接口的相同点1. 都通过继承实现且不能直接实例化两者都不能用new直接创建实例Animal animal new Animal(); // 错误 IAnimal animal new IAnimal(); // 错误需要说明的是任何接口都无法实例化抽象类同样不能实例化而普通类只要不是抽象类就可以实例化。2. 都可以包含没有实现的抽象方法抽象方法只是对方法的定义没有具体实现必须在派生类中使用override重写后才能生效。例如Animal和IAnimal都定义了Run()和Eat()void Run(); void Eat();它们并没有真正的实现内容调用方只知道这两个方法存在并不知道具体怎么 Run、怎么 Eat。定义的意义在于只要声明了就可以确定这两个方法对一般的 Animal 都应该存在派生时再根据具体派生类的特点实现相应功能从而完成多态。还要注意一种情况Run对鸟类可能并不适用Fly对陆地动物也不存在。多态的处理办法是“不处理”而不处理本身也是一种多态。四、分别用抽象类和接口派生 Dog下面以Animal和IAnimal为基础分别用抽象类和接口的方式派生出一个Dog类。方式一从抽象类Animal派生public class Dog : Animal { public override void Run() { Console.WriteLine(Dog runs.); } public override void Eat() { Console.WriteLine(Dog eat.); } }方式二从接口IAnimal派生public class Dog : IAnimal { public void Run() { Console.WriteLine(Dog runs.); } public void Eat() { Console.WriteLine(Dog eat.); } }可以看出两种方式在派生类中的实现写法基本一致差别主要体现在继承语法和修饰符上。五、抽象类与接口的区别相同点比较容易理解两者的区别更需要重点掌握。下面先列出区别再逐一举例说明。1. 接口支持多继承抽象类不支持public interface IEat { void Eat(); } public interface IRun { void Run(); } public class Dog : IEat, IRun { public void Eat() { Console.WriteLine(Dog eat.); } public void Run() { Console.WriteLine(Dog runs.); } }上面的Dog类同时实现了IEat和IRun两个接口而 C# 中一个类只能继承一个基类抽象类无法实现多继承。2. 接口只能定义抽象规则抽象类可以提供已实现的成员抽象类既可以定义规则也可以提供已经实现的成员例如下面的Eat就有具体实现public abstract class Animal { public abstract void Run(); public void Eat() { Console.WriteLine(Animal Eat.); } }而接口中的成员默认都是待实现的约定不能直接给出方法体C# 8.0 之前的默认接口方法除外。3. 接口侧重行为规范抽象类可承载更多成员接口是一组行为规范只提供方法签名主要强调方法重写override的概念可以理解为一个不完全的类抽象类中还可以包含属性、事件等内容成员既可以有初值也可以完全抽象。4. 接口不能定义字段抽象类可以接口只包含方法、属性、索引器、事件的签名不能定义字段也不能包含带实现的方法抽象类则可以定义字段、属性以及带实现的方法。public abstract class Animal { private string animalName; // 非抽象属性 public string AnimalName { get { return animalName; } set { animalName value; } } // 抽象属性 public abstract float Weight { get; set; } public abstract void Run(); public void Eat() { Console.WriteLine(Animal Eat.); } }5. 接口可作用于值类型和引用类型抽象类只能作用于引用类型接口可以作用于值类型和引用类型例如struct可以继承接口但不能继承类抽象类只能作用于引用类型。六、总结与选用建议总体来看接口的使用面比抽象类更广抽象类的限制更多但功能也更强大体现的是继承关系。当类的发展不需要受到过多限制和约束时可以使用接口让实现类自由发展此时实现接口的类就是一个相对稳定的类这也体现了接口保持类稳定性的作用。两者都源于面向对象思想具备很大的相似性。至于何时用抽象类、何时用接口并没有绝对定论应结合程序规模、设计方式和后续扩展空间来判断这需要扎实的理论基础和大量的实践经验。实践中的常见建议是需要共享公共实现、维护字段或状态时优先考虑抽象类。只需要约定一组行为、希望实现类自由扩展或需要多继承能力时优先考虑接口。两者可以配合使用用接口定义契约用抽象类提供默认实现。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑