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);
        }

    }
}
相关推荐
Murphy20232 小时前
.net4.0 调用API(form-data)上传文件及传参
开发语言·c#·api·httpwebrequest·form-data·uploadfile·multipart/form-
我曾经是个程序员2 小时前
C#Directory类文件夹基本操作大全
服务器·开发语言·c#
鸿喵小仙女4 小时前
C# WPF读写STM32/GD32单片机Flash数据
stm32·单片机·c#·wpf
一个不正经的林Sir4 小时前
C#WPF基础介绍/第一个WPF程序
开发语言·c#·wpf
码农君莫笑14 小时前
使用blazor开发信息管理系统的应用场景
数据库·信息可视化·c#·.net·visual studio
可喜~可乐16 小时前
C# WPF开发
microsoft·c#·wpf
666和77720 小时前
C#的单元测试
开发语言·单元测试·c#
小码编匠21 小时前
WPF 星空效果:创建逼真的宇宙背景
后端·c#·.net
向宇it1 天前
【从零开始入门unity游戏开发之——unity篇02】unity6基础入门——软件下载安装、Unity Hub配置、安装unity编辑器、许可证管理
开发语言·unity·c#·编辑器·游戏引擎
yngsqq1 天前
一键打断线(根据相交点打断)——CAD c# 二次开发
windows·microsoft·c#