什么是扩展方法?virtual方法或abstract方法有什么区别?Interface与 Abstract Class有什么区别?
一、什么是扩展方法?
结论:向现有类型添加方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型。扩展方法是一种静态方法,但可以像扩展类型上的实例方法一样进行调用。
使用场景:对于原始源不受控制、派生对象不合适或不可用,或者不应在功能适用范围之外公开功能的情况,扩展方法是一个不错的选择。
概念:扩展方法被定义为静态方法,但它们是通过实例方法语法进行调用的。 它们的第一个参数指定方法操作的类型,参数使用this修饰符修饰。
举个栗子:
1、定义扩展方法
namespace ExtensionMethods { public static class StringExtensions { public static int WordCount(this String str) { return str.Split(new char[] { ' ', '.', '?' },StringSplitOptions.RemoveEmptyEntries).Length; } } }
2、调用扩展方法
方法1、 string s = "Hello Extension Methods"; int i = s.WordCount(); 方法2、string s = "Hello Extension Methods"; int i = MyExtensions.WordCount(s);
可以使用扩展方法来扩展类或接口,但不能重写扩展方法。 与接口或类方法具有相同名称和签名的扩展方法永远不会被调用。 编译时,扩展方法的优先级总是比类型本身中定义的实例方法低。
换句话说,如果某个类型具有一个名为 Process(int i) 的方法,而你有一个具有相同签名的扩展方法,则编译器总是绑定到该实例方法。 当编译器遇到方法调用时,它首先在该类型的实例方法中寻找匹配的方法。 如果未找到任何匹配方法,编译器将搜索为该类型定义的任何扩展方法,并且绑定到它找到的第一个扩展方法。
参考:扩展方法 - C# 编程指南 | Microsoft Docs
二、virtual方法或abstract方法有什么区别?
结论:
多个子类中有部分类行为相同,使用virtual方法在基类中提供默认实现
所有子类实现迥异,但他们应具有相同的行为,使用abstract关键字标记
使用场景:
virtual方法告诉子类:我很贴心地提供了默认实现,你可以直接使用我,如果你觉得我不够好,你可以重写我。
abstract方法告诉子类:虽然我没办法提供默认实现,但是我警告你,如果你继承了我你就必须实现我,否则你将无法通过编译。
概念:
virtual 关键字声明方法可以在派生类中被重写
abstract关键字声明方法必须由派生自抽象类的非抽象类实现
栗子:
/// <summary> /// abstract标记的类无法实例化 /// </summary> public abstract class BaseClass { public string Property { get; set; } //如果你继承了BaseClass你必须实现MustImplementMethod方法 public abstract void MustImplementMethod(); //如果你继承了BaseClass你可以根据需要重写YouCanOverride方法 public virtual void CanOverrideMethod() { Console.WriteLine("Hello World"); } //普通方法 public void NormalMethod() { Console.WriteLine(this.Property); } } /// <summary> /// 子类 /// </summary> public class ChildClass : BaseClass { /// <summary> /// 如果继承了BaseClass,必须实现MustImplementMethod方法 /// </summary> public override void MustImplementMethod() { throw new NotImplementedException(); } /// <summary> /// 如果继承了BaseClass,可以选择重写CanOverrideMethod方法 /// </summary> public override void CanOverrideMethod() { base.CanOverrideMethod(); base.Property = "Hello World"; base.NormalMethod(); } }
三、Interface与 Abstract Class有什么区别?
结论:
1、接口是一个契约,是一个共识,它不关心继承者是什么,它只在乎继承者是否实现了它所声明的一切
2、抽象类希望在多个相关对象之间实现相同的行为,它希望继承者来自同一族群,告知继承者你们应该像我声明的那样一致行动
使用场景:
考虑使用接口,如果:
1、希望不相关的类实现你的接口.
2、希望指定特定的行为,但不关心由谁实现它的行为
3、想要利用多重继承的优势
考虑使用抽象类如果:
1、希望在几个密切相关的类之间共享代码
2、希望扩展抽象类的类具有许多公共的方法或字段,或者需要公共以外的访问修饰符
概念:
接口定义了契约。实现该契约的任何类或结构都必须提供接口中定义的成员的实现。
关键字 abstract 使你能够创建不完整的类和类成员,这些类和类成员必须在派生类中实现。
栗子:
/// <summary> /// 定义接口 /// </summary> interface IInterface { void ContractMethod(); } /// <summary> /// 继承自抽象类与接口 /// 继承BaseClass似乎在说:我ImplementationClass与BaseClass是一种类 /// 继承IInterface似乎在说:我遵循了IInterface声明的协议 /// </summary> public class ImplementationClass : BaseClass,IInterface { /// <summary> /// 实现接口 /// </summary> public void ContractMethod() { throw new NotImplementedException(); } /// <summary> /// 实现抽象类 /// </summary> public override void MustImplementMethod() { throw new NotImplementedException(); } }
参考:oop - Interface vs Abstract Class (general OO) - Stack Overflow