【C#】抽象类和接口的区别

本文分析了C#中抽象类和接口在静态成员、实例成员以及抽象/虚拟修饰符上的区别,强调了C#11后接口静态属性和方法的新特性,以及在实现和编译要求上的变化。
namespace cs {
    public partial class Program {
        public abstract class A {
            // static members
            // abstract and virtual modifiers are not allowed on fields
            public static int P1SF;
            protected internal static int PISF;
            internal static int InSF;
            protected static int P2SF;
            private static int P3SF;
            // You cannot use abstract / virtual modifier on static properties of an abstract class
            public static int P1S_P { get; set; }
            protected internal static int PIS_P { get; set; }
            internal static int InS_P { get; set; }
            protected static int P2S_P { get; set; }
            private static int P3S_P { get; set; }
            // You cannot use abstract / virtual modifier on static methods of an abstract class
            public static void P1S_M() { }
            protected internal static void PIS_M() { }
            internal static void InS_M() { }
            protected static void P2S_M() { }
            private static void P3S_M() { }
            // instance members
            // abstract and virtual modifiers are not allowed on fields
            public int P1_F;
            protected internal int PI_F;
            internal int In_F;
            protected int P2_F;
            private int P3_F;
            public int P1__P { get; set; }
            protected internal int PI__P { get; set; }
            internal int In__P { get; set; }
            protected int P2__P { get; set; }
            private int P3__P { get; set; }
            public abstract int P1_AP { get; set; }
            protected internal abstract int PI_AP { get; set; }
            internal abstract int In_AP { get; set; }
            protected abstract int P2_AP { get; set; }
            // abstract members cannot be private
            public virtual int P1_VP { get; set; }
            protected internal virtual int PI_VP { get; set; }
            internal virtual int In_VP { get; set; }
            protected virtual int P2_VP { get; set; }
            // virtual members cannot be private
            public void P1__M() { }
            protected internal void PI__M() { }
            internal void In__M() { }
            protected void P2__M() { }
            private void P3__M() { }
            public abstract void P1_AM();
            protected internal abstract void PI_AM();
            internal abstract void In_AM();
            protected abstract void P2_AM();
            // abstract members cannot be private
            public virtual void P1_VM() { }
            protected internal virtual void PI_VM() { }
            internal virtual void In_VM() { }
            protected virtual void P2_VM() { }
            // virtual members cannot be private
        }
        public interface I {
            // static members
            // abstract and virtual modifiers are not allowed on fields
            public static int P1SF;
            protected internal static int PISF;
            internal static int InSF;
            protected static int P2SF;
            private static int P3SF;
            // In C# 11 (.NET 7), you can use abstract / virtual modifier on static properties of an interface
            public static int P1S_P { get; set; }
            protected internal static int PIS_P { get; set; }
            internal static int InS_P { get; set; }
            protected static int P2S_P { get; set; }
            private static int P3S_P { get; set; }
            public static abstract int P1SAP { get; set; }
            protected internal static abstract int PISAP { get; set; }
            internal static abstract int InSAP { get; set; }
            protected static abstract int P2SAP { get; set; }
            public static virtual int P1SVP { get; set; }
            protected internal static virtual int PISVP { get; set; }
            internal static virtual int InSVP { get; set; }
            protected static virtual int P2SVP { get; set; }
            // In C# 11 (.NET 7), you can use abstract / virtual modifier on static methods of an interface
            public static void P1S_M() { }
            protected internal static void PIS_M() { }
            internal static void InS_M() { }
            protected static void P2S_M() { }
            private static void P3S_M() { }
            public static abstract void P1SAM();
            protected internal static abstract void PISAM();
            internal static abstract void InSAM();
            protected static abstract void P2SAM();
            public static virtual void P1SVM() { }
            protected internal static virtual void PISVM() { }
            internal static virtual void InSVM() { }
            protected static virtual void P2SVM() { }
            // instance members
            // interfaces cannot have instance fields
            public int P1__P { get; set; }
            protected internal int PI__P { get; set; }
            internal int In__P { get; set; }
            protected int P2__P { get; set; }
            private int P3__P { get { return 0; } set { } }
            public abstract int P1_AP { get; set; }
            protected internal abstract int PI_AP { get; set; }
            internal abstract int In_AP { get; set; }
            protected abstract int P2_AP { get; set; }
            // abstract members cannot be private
            public virtual int P1_VP { get { return 0; } set { } }
            protected internal virtual int PI_VP { get { return 0; } set { } }
            internal virtual int In_VP { get { return 0; } set { } }
            protected virtual int P2_VP { get { return 0; } set { } }
            // virtual members cannot be private
            public void P1__M() { }
            protected internal void PI__M() { }
            internal void In__M() { }
            protected void P2__M() { }
            private void P3__M() { }
            public abstract void P1_AM();
            protected internal abstract void PI_AM();
            internal abstract void In_AM();
            protected abstract void P2_AM();
            // abstract members cannot be private
            public virtual void P1_VM() { }
            protected internal virtual void PI_VM() { }
            internal virtual void In_VM() { }
            protected virtual void P2_VM() { }
            // virtual members cannot be private
        }
        public class C : A {
            public override int P1_AP { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
            protected override int P2_AP { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
            protected internal override int PI_AP { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
            internal override int In_AP { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
            public override void P1_AM() => throw new NotImplementedException();
            protected override void P2_AM() => throw new NotImplementedException();
            protected internal override void PI_AM() => throw new NotImplementedException();
            internal override void In_AM() => throw new NotImplementedException();
        }
        public class D : I {
            static int I.P1SAP { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
            static int I.PISAP { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
            static int I.InSAP { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
            static int I.P2SAP { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
            int I.P1__P { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
            int I.PI__P { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
            int I.In__P { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
            int I.P2__P { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
            int I.P1_AP { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
            int I.PI_AP { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
            int I.In_AP { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
            int I.P2_AP { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
            static void I.InSAM() => throw new NotImplementedException();
            static void I.P1SAM() => throw new NotImplementedException();
            static void I.P2SAM() => throw new NotImplementedException();
            static void I.PISAM() => throw new NotImplementedException();
            void I.In_AM() => throw new NotImplementedException();
            void I.P1_AM() => throw new NotImplementedException();
            void I.P2_AM() => throw new NotImplementedException();
            void I.PI_AM() => throw new NotImplementedException();
        }
        public class E : A, I {
            public override int P1_AP { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
            protected override int P2_AP { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
            protected internal override int PI_AP { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
            internal override int In_AP { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
            public override void P1_AM() => throw new NotImplementedException();
            protected override void P2_AM() => throw new NotImplementedException();
            protected internal override void PI_AM() => throw new NotImplementedException();
            internal override void In_AM() => throw new NotImplementedException();
            static int I.P1SAP { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
            static int I.PISAP { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
            static int I.InSAP { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
            static int I.P2SAP { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
            int I.PI__P { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
            int I.In__P { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
            int I.P2__P { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
            int I.PI_AP { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
            int I.In_AP { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
            int I.P2_AP { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
            static void I.P1SAM() => throw new NotImplementedException();
            static void I.InSAM() => throw new NotImplementedException();
            static void I.P2SAM() => throw new NotImplementedException();
            static void I.PISAM() => throw new NotImplementedException();
            void I.In_AM() => throw new NotImplementedException();
            void I.P2_AM() => throw new NotImplementedException();
            void I.PI_AM() => throw new NotImplementedException();
        }
        public static void Main(string[] args) {
            C c = new();
            D d = new();
            E e = new();
            Console.WriteLine(c);
            Console.WriteLine(d);
            Console.WriteLine(e);
        }
    }
}

相同点

  • abstract 和 virtual 关键字均不可修饰字段,但可以修饰属性和方法。
  • abstract 和 virtual 成员不能是 private 访问控制。
  • 对于每个成员,abstract 和 virtual 关键字只能使用一个,或者都不使用。
  • 均不可实例化。

不同点

  • abstract 和 virtual 关键字均不可修饰抽象类的静态属性和方法,但自 C# 11 起,可以修饰接口的静态属性和方法。故而,接口的非 private 静态抽象属性和非 private 静态抽象方法均必须实现,否则编译不通过。
  • 在抽象类中,不被 abstract 修饰但省略了方法体的方法会令编译报错(要求添加 abstract,extern 或 partial 关键字)。而在接口中,不被 abstract 修饰但省略了方法体(不具有默认实现)的方法本身不会令编译报错,但必须提供这些方法的实现。
  • 在抽象类中,实现 abstract 属性和 abstract 方法时,需要使用 override 关键字。但在接口中,实现属性和方法时,不需要使用 override 关键字,即便该方法被 abstract 修饰。
  • 抽象类可以含有实例字段,但接口不可含有实例字段。
  • 抽象类的非 private 一般实例属性(非 abstract 且非 virtual)不要求必须实现,而接口的非 private 一般实例属性必须提供实现,否则编译不通过。
  • 抽象类的 private 一般实例属性及 virtual 的实例属性可以使用默认的 get accessor 和 set accessor,但接口的 private 一般实例属性及 virtual 的实例属性不可使用默认的 get accessor 和 set accessor。
  • 一个类只能继承单一的父类(包括抽象类),但可以实现多个接口。
  • 虽然在很多时候将抽象类和接口互换并不影响程序的行为,然而习惯上,抽象类及其子类描述一个实体,例如System.IO.Stream, Microsoft.AspNetCore.Mvc.Controller;而接口要求其实现类具有某个行为或性质,例如:System.Collections.IEnumerable, System.IComparable
### C#抽象类接口区别 #### 定义方式不同 抽象类是一种特殊的类,允许定义部分实现的方法属性。可以通过 `abstract` 关键字标记类及其成员[^2]。 ```csharp public abstract class Animal { public abstract void MakeSound(); } ``` 接口则完全由未实现的签名组成,不允许提供任何具体实现[^3]。 ```csharp public interface IAnimal { void MakeSound(); } ``` #### 继承机制差异 C# 支持单一继承模式,这意味着一个类只能继承自另一个类。然而,这并不妨碍该类同时实现实现多个接口。 ```csharp // 单一继承 public class Dog : Animal { ... } // 多重接口实现 public class Cat : Animal, IFeline, ICarnivore { ... } ``` #### 成员特性对比 - **字段**:抽象类能够拥有字段;而接口仅能包含方法、属性、事件或索引器声明,无法容纳数据存储单元即字段。 - **默认实现**:从 C# 8.0 开始,接口支持为方法提供默认实现,但这不是强制性的。 #### 实例化能力 抽象类本身不可实例化,但其非抽象派生类可以被创建对象并调用虚函数或覆写的成员。 ```csharp var dog = new Dog(); // 正确 dog.MakeSound(); var animal = new Animal(); // 错误,因为Animal是抽象类 ``` 对于接口而言,永远不可能直接生成其实例,必须借助实现了此接口的具体类型来进行操作。 ```csharp IAnimal cat; cat = new Cat(); // 需要通过已实现接口的具体类来赋值 cat.MakeSound(); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值