.Net 一套接口多实现

接口(interface)可理解为规范、标准、协议。接口是用来约束各方都在同一组规范下工作。

电脑外设USB接口,各个品牌商家生产的U盘、鼠标都能够被电脑主板识别并工作,这是因为个生产商都遵循实现了USB接口协议。

在编程中接口应用非常广泛,例如IDbConnection接口,这是一组数据库连接的接口,由各个数据库驱动实现,因此.Net可以操作多种数据库。

一套接口多实现的基本结构如下

实现思路是,通过在各实现类上使用Attribute进行标记,然后定义一个实例获取类,通过反射获取所有实现该接口并且标记了的实现类,并将各个实现类通过IOC注册,然后通过标记的类型获取对应的实现类。

接下来是demo演示

定义服务标记

    [AttributeUsageAttribute(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public class MultiServiceTypeAttribute : Attribute
{
public string ServiceType { get; private set; }
public MultiServiceTypeAttribute(string serviceType)
{
ServiceType = serviceType;
}
}

定义接口IMultiInterface

    public interface IMultiInterface
{
void Do();
}

定义实现类AMultiInterfaceImplA并标记

    [MultiServiceTypeAttribute("A")]
public class MultiInterfaceImplA : IMultiInterface
{
public void Do()
{
Console.WriteLine("这是A实现的调用");
}
}

定义实现类BMultiInterfaceImplB并标记

    [MultiServiceTypeAttribute("B")]
public class MultiInterfaceImplB : IMultiInterface
{
public void Do()
{
Console.WriteLine("这是B实现的调用");
}
}

将接口与实现添加到IOC容器,这里使用 Microsoft.Extensions.DependencyInjection.dllMicrosoft.Extensions.DependencyInjection.Abstractions.dll两个库来实现简易IOC容器

    public class ServiceLoader
{
private readonly ServiceCollection __ioc = new ServiceCollection();
private ServiceProvider __iocServiceProvider;
private static object _lock = new object(); private static ServiceLoader _inst; public static ServiceLoader Inst
{
get
{
if (_inst == null)
{
lock (_lock)
{
if (_inst == null)
{
_inst = new ServiceLoader();
_inst.Init();
}
}
}
return _inst;
}
} private void Init()
{
var tps = typeof(IMultiInterface).Assembly.GetTypes().Where(x =>
x.GetInterfaces().Any(_ => _.Name == nameof(IMultiInterface)));
foreach (var item in tps)
{
if (item.IsClass)
{
Inst.AddTransient(typeof(IMultiInterface), item);
}
}
Interlocked.Exchange(ref __iocServiceProvider, Inst.__ioc.BuildServiceProvider());
} private void AddTransient(Type iface, Type impl)
{
__ioc.AddTransient(iface, impl);
}
}

根据标记的类型获取对应的接口实现。在ServiceLoader中继续添加以下方法

        public IMultiInterface GetService(string serviceType)
{
var svcList = __iocServiceProvider.GetServices<IMultiInterface>();
var svc = svcList.FirstOrDefault(x => x.GetType().GetCustomAttribute<MultiServiceTypeAttribute>()?.ServiceType == serviceType);
if (svc == null)
{
//Console.WriteLine($@"未找到 {serviceType} 服务实现,使用默认实现");
// 如果有默认实现类,这里可选择调用默认实现
//svc = svcList.FirstOrDefault(x => x.GetType().GetCustomAttribute<MultiServiceTypeAttribute>()?.ServiceType == "__default__");
throw new Exception($"未找到 {serviceType} 服务实现");
} return svc;
}

通过ServiceLoader.Inst.GetService("serviceType").Do();来获取对应的接口实例,入参就是各个实现类上标记的类型,并调用接口。

调用示例如下

至此实现了一接口多实现的雏形。

.Net 一套接口多实现的更多相关文章

  1. Linux网络编程系列-套接口选项控制

    获取和设置套接口选项的方法有: getsockopt/setsockopt fcntl ioctl getsockopt/setsockopt 这两个函数仅用于套接口(socket)的设置,另外两个函 ...

  2. UDP套接口编程

    常用的UDP实现的程序:DNS域名系统,NFS网络文件系统,SNMP简单网络管理协议 ssize_t recvfrom(int sockfd,void *buff,size_t nbytes,int ...

  3. fuser:用文件或者套接口表示进程

    fuser:用文件或者套接口表示进程 作用:fuser命令用文件或者套接口表示进程. 用法:fuser [-a | -s | -c] [-4 | -6] [-n space] [-k [-i] [-s ...

  4. socket , 套接口还是套接字,傻傻分不清楚

    socket 做网络通信的朋友大都对socket这个词不会感到陌生,但是它的中文翻译是叫套接口还是套接字呢,未必大多数朋友能够分清,今天我们就来聊聊socket的中文名称. socket一词的起源 在 ...

  5. Socket调用Close后如何终止套接口的问题

    setsockopt 设置 SO_LINGER 选项 此选项指定函数close对面向连接的协议如何操作(如TCP).内核缺省close操作是立即返回,如果有数据残留在套接口缓冲区中则系统将试着将这些数 ...

  6. 值得收藏的TCP套接口编程文章

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由jackieluo发表于云+社区专栏 TCP客户端-服务器典型事件 下图是TCP客户端与服务器之间交互的一系列典型事件时间表: 首先启 ...

  7. 设置套接口的选项setsockopt的用法

    body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...

  8. 套接口socket编程(Client/Server编程实例)

    基本概念 套接口也就是网络中的ID.网络通信,归根到底还是进程间通信(不同计算机上的进程间的通信).在网络中,每一个节点(计算机或路由器)都有一个网络地址,也就是IP地址. IP地址:在网络中唯一标识 ...

  9. UNIX网络编程读书笔记:原始套接口

    概述 应用程序可以绕过传输层而直接使用IPv4和IPv6,这称为原始套接口(raw socket).http://www.cnblogs.com/nufangrensheng/p/3583435.ht ...

  10. UNIX网络编程读书笔记:基本SCTP套接口编程

    概述 SCTP是一个较新的传输协议,于2000年在IETF得到标准化(TCP是在1981年标准化的).它最初是为满足不断增长的IP电话市场设计的:具体地说,就是穿越因特网传输电话信令. SCTP是一个 ...

随机推荐

  1. 如何打开 plist 文件

      plist 文件是一种用于存储应用程序配置信息的文件格式,其中包含应用程序的各种设置和数据.在过去,plist 文件通常是以.plist 格式存储的.然而,随着时间的推移,人们开始使用.plist ...

  2. SkyWalking的学习之一

    SkyWalking的学习之一 前言 最近在学习应用调优诊断等内容. 现在实际工作中实质上的拆分和微服务在售前阶段 所以真正用到链路的地方比较少. 但是人生都是要向前看的. 想着一方面提高自己. 一方 ...

  3. 容器云平台监控告警体系(五)—— Prometheus发送告警机制

    1.概述 在Prometheus的架构中告警被划分为两个部分,在Prometheus Server中定义告警规则以及产生告警,Alertmanager组件则用于处理这些由Prometheus产生的告警 ...

  4. docker-compose一键部署java开源项目

    这一年干的很多事都是为了降低我的开源项目消息推送平台austin使用门槛. 如果想学Java项目的,强烈推荐我的开源项目消息推送平台Austin(8K stars) ,可以用作毕业设计,可以用作校招, ...

  5. C#实现右下角托盘程序,默认不显示窗体,关闭窗体时隐藏而不退出

    Windows右下角托盘程序是Windows系统的一大特色.在某些场景非常适用. 因业务需要实现一个后台程序,需要开机自动启动,默认不显示窗体,点击系统右下角托盘图标时显示窗体,关闭窗体时隐藏而不退出 ...

  6. fiddler简单使用

    fiddler简单使用 下载 网上找资源下载 安装 一路同意就可以了 使用 1.配置https证书 这些项全选,然后信任证书,就可以抓到ssl的包 2.改变网络端口 3.改写网页代码 以爬虫网为例,先 ...

  7. uni-app Pages.json配置

    https://uniapp.dcloud.net.cn/collocation/pages.html pages.json 文件用来对 uni-app 进行全局配置,决定页面文件的路径.窗口样式.原 ...

  8. PictureBox保存图片照片到数据库

    Private Sub PAPHOTO_SAVE() Try If TxtPictureURL.Text.ToString <> "" Then Dim SQL_Str ...

  9. .NET6 + EF Core + MySQL 创建实体和数据库、EFCore 数据迁移

    前言 接上期文章<.NET6项目连接数据库方式方法>,有人问了我几个问题,现在就这几个问题,拓展延申一下创建实体类.数据库.把ORM框架和数据迁移都写进去. 安装ORM框架,这里我们采用E ...

  10. 使用weexplus + vue开发APP的填坑之旅

    最近需要撸一个app来满足用户的需求,找来找去发现flutter不错,决定用它但是时间不够(准备挤出时间再去研究flutter),进度又催得紧,最后决定选weex这个上手快些,说干就干打开官网跟着ap ...