C#中接口、委托的相关使用

什么是接口

在 C# 中,接口(Interface)是一种用于定义行为契约的类型。它是一个抽象的概念,描述了类或结构体应该具有的成员(方法、属性、事件等)的集合,而不提供具体的实现细节。

接口定义了一组方法、属性和事件的签名,这些成员可以被实现接口的类或结构体来实现。通过实现接口,类或结构体可以遵循接口所定义的契约,并提供自己的具体实现。

在 C# 中,使用 interface 关键字来声明一个接口。以下是一个简单的接口示例:

csharp 复制代码
public interface IMyInterface
{
    void Method1();
    string Method2();
    int Property { get; set; }
    event EventHandler MyEvent;
}

在上面的示例中,IMyInterface 接口定义了一个名为 Method1 的无返回值方法,一个名为 Method2 的返回类型为 string 的方法,一个名为 Property 的读写属性,以及一个名为 MyEvent 的事件。

类或结构体可以通过使用 classstruct 关键字来实现接口,并提供接口中定义的成员的具体实现。以下是一个实现了上述接口的类的示例:

csharp 复制代码
public class MyClass : IMyInterface
{
    public void Method1()
    {
        // 实现 Method1 的具体代码
    }

    public string Method2()
    {
        // 实现 Method2 的具体代码
        return "";
    }

    public int Property { get; set; }

    public event EventHandler MyEvent;
}

通过实现接口,MyClass 类遵循了 IMyInterface 接口所定义的契约,并提供了对应成员的具体实现。

接口在 C# 中被广泛用于实现多态和代码组织的目的,它允许定义统一的契约,并通过不同的实现类来实现具体的行为。

什么是委托

在 C# 中,委托(Delegate)是一种类型,用于表示对一个或多个方法的引用。委托可以像其他对象一样传递、存储和调用方法,使得方法能够像数据一样被处理。

委托提供了一种方便的方式来实现事件处理、回调函数和函数指针等功能。它允许将方法作为参数传递给其他方法,以及将方法作为返回值返回。

在 C# 中,委托通过声明委托类型来定义。委托类型指定了可以被委托引用的方法的签名。以下是一个简单的委托类型示例:

csharp 复制代码
public delegate void MyDelegate(string message);

上述示例定义了一个名为 MyDelegate 的委托类型,它可以引用一个具有一个 string 参数且返回类型为 void 的方法。

可以使用委托类型来创建委托实例,然后将其用于引用具有匹配签名的方法。以下是一个示例:

csharp 复制代码
public class MyClass
{
    public void Method1(string message)
    {
        Console.WriteLine("Method1: " + message);
    }

    public void Method2(string message)
    {
        Console.WriteLine("Method2: " + message);
    }
}

public class Program
{
    public static void Main()
    {
        MyClass obj = new MyClass();

        MyDelegate del = obj.Method1;
        del("Hello");  // 调用 Method1

        del = obj.Method2;
        del("World");  // 调用 Method2
    }
}

在上述示例中,MyClass 类定义了两个具有匹配签名的方法 Method1Method2。然后,通过委托类型 MyDelegate 创建了 del 委托实例,并将其分别引用了 Method1Method2

通过调用委托实例,可以间接调用被引用的方法,实现了方法的动态调用。

委托在 C# 中被广泛用于事件处理、异步编程和回调机制等场景,提供了灵活且可扩展的方法引用机制。

通过实例来运用接口和委托

场景

实现对周黑鸭工厂的产品生产统一管理,主要产品包括鸭脖和鸭翅。武汉工厂能生生产鸭脖和鸭翅,南京工厂只能生产鸭翅,长沙工厂只能生产鸭脖。

代码实现

  • 定义接口 IProductionFactory,包含生产鸭脖和鸭翅的方法。

    csharp 复制代码
        public interface IProductionFactory
        {
            void ProduceDuckNecks();
            void ProduceDuckWings();
        }
  • 定义类 WuhanFactory、NanjingFactory、ChangshaFactory 分别实现接口 IProductionFactory,用于具体的生产工厂。

    说明:这里对于类中不能生产的处理方法是抛出异常

    1. 武汉工厂
    csharp 复制代码
        class WuhanFactory : IProductionFactory
        {
            public void ProduceDuckNecks()
            {
                Console.WriteLine("Wuhan factory produce duck necks...");
            }
            public void ProduceDuckWings()
            {
                Console.WriteLine("Wuhan factory produce duck wings...");
            }
        }
    1. 南京工厂
    csharp 复制代码
        class NanjingFactory : IProductionFactory
        {
            public void ProduceDuckNecks()
            {
                throw new NotImplementedException("Error: Nanjing factory cannot produce duck necks!");
            }
            public void ProduceDuckWings()
            {
                Console.WriteLine("Nanjing factory produce duck wings...");
            }
        }
    1. 长沙工厂
    csharp 复制代码
        class ChangshaFactory : IProductionFactory
        {
            public void ProduceDuckNecks()
            {
                Console.WriteLine("Changsha factory produce duck necks...");
            }
            public void ProduceDuckWings()
            {
                throw new NotImplementedException("Error: Changsha factory cannot produce duck wings!");
            }
        }
  • 使用委托 ProductionDelegate 定义生产委托。

    csharp 复制代码
        public delegate void ProductionDelegate();
  • 在 Main 函数中,创建不同工厂的实例,并通过生产委托进行生产。

    说明:抽离出FactoryProduct,函数入参为委托类型,方便对委托进行统一化调用,同时进行了异常处理,提高代码复用性

    csharp 复制代码
        public static void FactoryProduct(ProductionDelegate productionDelegate)
        {
            // 无误则正常调用
            try
            {
                productionDelegate();
            }
            // 异常则抛出异常
            catch (NotImplementedException e)
            {
                Console.WriteLine(e.Message);
            }
        }
        public static void Main(string[] args)
        {
            // 创建工厂实例
            IProductionFactory wuhanFactory, nanjingFactory, changshaFactory;
            wuhanFactory = new WuhanFactory();
            nanjingFactory = new NanjingFactory();
            changshaFactory = new ChangshaFactory();
    
            // 实现委托
            ProductionDelegate wuhanDelegate, nanjingDelegate, changshaDelegate;
            // 武汉
            wuhanDelegate = wuhanFactory.ProduceDuckNecks;
            wuhanDelegate += wuhanFactory.ProduceDuckWings;
            // 南京
            nanjingDelegate = nanjingFactory.ProduceDuckWings;
            // 长沙
            changshaDelegate = changshaFactory.ProduceDuckNecks;
    
            // 通过委托进行生产
            FactoryProduct(wuhanDelegate);
            FactoryProduct(nanjingDelegate);
            FactoryProduct(changshaDelegate);
        }
  • 运行结果

    • 正常情况
    • 异常情况

      csharp 复制代码
         wuhanDelegate = wuhanFactory.ProduceDuckNecks;
         wuhanDelegate += wuhanFactory.ProduceDuckWings;
         // 南京
         nanjingDelegate = nanjingFactory.ProduceDuckWings;
         nanjingDelegate += nanjingFactory.ProduceDuckNecks;
         // 长沙
         changshaDelegate = changshaFactory.ProduceDuckNecks;
         changshaDelegate += changshaFactory.ProduceDuckWings;

小结

通过接口我们可以实现对类的统一定义,定义接口完成顶层设计,而将具体的实现交给类,而不是使用派生和继承的方式,具有灵活性、解耦合、实现多态、接口隔离原则的特点,优化了多继承问题的解决;而使用委托则是统一了调用入口,让函数的调用更加简洁,统一,使代码的可读性更高,同时在本次代码实例中通过异常抛出的方法描述错误调用接口会有什么样的后果,而不是用空函数来取代这个部分,使得代码的可维护性更高,我们也能更直观的感受到接口的调用。

END - 完整代码

csharp 复制代码
    using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 鸭脖和鸭翅_接口和委托
{
    internal class Program
    {
        public interface IProductionFactory
        {
            void ProduceDuckNecks();
            void ProduceDuckWings();
        }
        class WuhanFactory : IProductionFactory
        {
            public void ProduceDuckNecks()
            {
                Console.WriteLine("Wuhan factory produce duck necks...");
            }
            public void ProduceDuckWings()
            {
                Console.WriteLine("Wuhan factory produce duck wings...");
            }
        }

        class NanjingFactory : IProductionFactory
        {
            public void ProduceDuckNecks()
            {
                throw new NotImplementedException("Error: Nanjing factory cannot produce duck necks!");
            }
            public void ProduceDuckWings()
            {
                Console.WriteLine("Nanjing factory produce duck wings...");
            }
        }
        class ChangshaFactory : IProductionFactory
        {
            public void ProduceDuckNecks()
            {
                Console.WriteLine("Changsha factory produce duck necks...");
            }
            public void ProduceDuckWings()
            {
                throw new NotImplementedException("Error: Changsha factory cannot produce duck wings!");
            }
        }
        public delegate void ProductionDelegate();
        public static void FactoryProduct(ProductionDelegate productionDelegate)
        {
            // 无误则正常调用
            try
            {
                productionDelegate();
            }
            // 异常则抛出异常
            catch (NotImplementedException e)
            {
                Console.WriteLine(e.Message);
            }
        }
        public static void Main(string[] args)
        {
            // 创建工厂实例
            IProductionFactory wuhanFactory, nanjingFactory, changshaFactory;
            wuhanFactory = new WuhanFactory();
            nanjingFactory = new NanjingFactory();
            changshaFactory = new ChangshaFactory();

            // 实现委托
            ProductionDelegate wuhanDelegate, nanjingDelegate, changshaDelegate;
            // 武汉
            wuhanDelegate = wuhanFactory.ProduceDuckNecks;
            wuhanDelegate += wuhanFactory.ProduceDuckWings;
            // 南京
            nanjingDelegate = nanjingFactory.ProduceDuckWings;
            //nanjingDelegate += nanjingFactory.ProduceDuckNecks;
            // 长沙
            changshaDelegate = changshaFactory.ProduceDuckNecks;
            //changshaDelegate += changshaFactory.ProduceDuckWings;

            // 通过委托进行生产
            FactoryProduct(wuhanDelegate);
            FactoryProduct(nanjingDelegate);
            FactoryProduct(changshaDelegate);
        }

    }
}
相关推荐
IT技术分享社区5 小时前
C#实战:使用腾讯云识别服务轻松提取火车票信息
开发语言·c#·云计算·腾讯云·共识算法
△曉風殘月〆12 小时前
WPF MVVM入门系列教程(二、依赖属性)
c#·wpf·mvvm
逐·風14 小时前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#
m0_6569747417 小时前
C#中的集合类及其使用
开发语言·c#
九鼎科技-Leo17 小时前
了解 .NET 运行时与 .NET 框架:基础概念与相互关系
windows·c#·.net
九鼎科技-Leo20 小时前
什么是 ASP.NET Core?与 ASP.NET MVC 有什么区别?
windows·后端·c#·asp.net·mvc·.net
.net开发20 小时前
WPF怎么通过RestSharp向后端发请求
前端·c#·.net·wpf
小乖兽技术20 小时前
C#与C++交互开发系列(二十):跨进程通信之共享内存(Shared Memory)
c++·c#·交互·ipc
幼儿园园霸柒柒20 小时前
第七章: 7.3求一个3*3的整型矩阵对角线元素之和
c语言·c++·算法·矩阵·c#·1024程序员节
平凡シンプル1 天前
C# EF 使用
c#