什么是扩展方法?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

posted @ 2022-07-21 14:41  wzyandi  阅读(160)  评论(0编辑  收藏  举报