论文阅读-2021ICAR-使用具有 DRL 的全局和本地地图信息进行无人机路径规划(点|障|单)

有障碍物+目标点

摘要

自主无人机 (UAV) 的路径规划方法
我们比较了覆盖路径规划 (CPP),其中无人机的目标是调查数据收集 (DH) 感兴趣的区域,其中无人机从分布式物联网 (IoT) 传感器设备收集数据。
基于电量有限的无人机,通过利用环境的结构化地图信息(全局地图和局部地图),我们在两个截然不同的任务场景中训练具有相同架构的双深度 Q 网络 (DDQN),以做出平衡各自任务目标与导航约束的运动决策。
通过引入一种利用环境的压缩全局地图和显示无人机代理附近的裁剪但未压缩的局部地图的新方法,我们证明了所提出的方法 可以有效地扩展到大型环境。
我们还扩展了以前的结果,用于概括控制策略,当场景参数发生变化时不需要重新训练,并提供关键地图处理参数对路径规划性能影响的详细分析。

Introduction

高效和安全的路径规划方法需要将任务目标与导航限制相结合,例如飞行时间和避障。包括区域覆盖路径规划 (CPP) [1],以及来自物联网 (IoT) 传感器节点的数据采集 (DH)。

  • CPP 旨在在给定的能量或路径长度限制内覆盖尽可能多的目标区域,同时避开障碍物或禁飞区。
  • 在 DH 场景中,无人机的目标是从分布在城市环境中的物联网设备收集数据,这意味着通过交替的视距 (LoS) 和非视距 (NLoS) 链路来挑战无线电信道条件无人机和物联网设备通过建筑物障碍物

当描述为 RL 问题时,DH 和 CPP 非常相似,因为路径规划问题的约束大多相同,只有目标函数发生变化(通过卷积网络层将空间地图信息直接馈送到 DRL )
这项工作的重点在于提出对现有 DRL 方法的改进,以解决以 CPP 和 DH 为例的广义、大规模 UAV 路径规划问题。

由于网络的大小、可训练参数和训练时间等量增加,使用地图作为直接输入对于大地图尺寸会产生问题。

我们引入了一个全局-局部地图方案来解决标准基于地图的输入的可扩展性问题。
使用全局地图,以代理位置为中心的完整环境地图的压缩版本,将地图上所有对象的一般信息提供给代理。
使用局部地图,裁剪为仅显示无人机代理的直接环境的本地地图提供了详细的本地信息。

因为DRL在先验知识和环境假设方面具有灵活性、DRL 推理的计算效率以及自主无人机控制任务的复杂性,这些任务通常是非凸优化问题并被证明可以在许多情况下是 NP-hard。

主要贡献

  • 展示其对两种截然不同的任务场景的适用性:覆盖路径规划和无线数据采集的路径规划,将提出的 DRL 方法确立为无人机路径规划的通用方法;
  • 引入一种新方法来利用全局-局部地图信息,使 DRL 用于路径规划能够有效地扩展到大型、现实的场景环境,与早期工作相比,网格单元要多一个数量级。
  • 通过将场景参数的控制策略泛化扩展到随机生成的目标区域,克服了先前 DRL CPP 方法 [1] 中固定目标区域的限制;
  • 分析和讨论关键地图处理参数对路径学习性能的影响。

Problem Formulation

展示了覆盖路径规划和数据采集路径规划的通用问题描述可以通过分为两部分来建立:环境和目标。

A. Environment and Uav Model

大小为 M×M∈N2 的正方形网格世界,单元大小为 c,其中 N 是自然数的集合。该环境包含指定的起始/着陆位置、管制禁飞区 (NFZ) 和障碍物。

地图可以通过张量 M∈BM×M×3 来描述,其中 B={0,1},地图层 1 中的起始/着陆区,地图层 2 中的 NFZ 和障碍物的联合,以及仅地图层 3 中的障碍物。

UAV 以恒定高度 h 穿过该环境,占据环境的一个单元。因此它的位置可以通过 p(t)∈N2 来定义。无人机的移动通过避免与障碍物碰撞和不进入 NFZ 来限制。

此外,无人机必须在属于起始区和着陆区的任何单元中开始和结束其任务,同时保持在由其初始电池电量确定的最大飞行时间内。 UAV 的电池电量 b(t) 在时间 t=0 时设置为 b0∈N,并且每执行一步减 1。

B. Target and Mission Definitions

Coverage Path Planning覆盖路径规划

在覆盖路径规划中,任务是通过在指定目标区域上方或附近飞行来覆盖指定目标区域,使其处于安装在无人机下方的类似相机的传感器的视野中。

目标区域可以通过 T(t)∈BM×M 来描述,其中每个元素描述了一个小区是否必须被覆盖。相机的当前视野可以用 V(t)∈BM×M 来描述,表示每个单元格是否在当前视野中。

这项工作中,视野是围绕当前无人机位置的 5×5 正方形。此外,建筑物可能会阻挡视线,这也包含在计算 V(t) 中。这会阻止无人机看到拐角处。

目标区域根据:T(t+1)=T(t)∧¬V(t)。其中 ∧ 和 ¬ 分别是单元格逻辑且,否定运算符。

环境中的障碍物单元不能作为覆盖目标,而起始区和着陆区以及禁飞区可以。目标是在最大飞行时间限制内覆盖尽可能多的目标区域

Data Harvesting数据收集

相反,无线数据采集路径规划的任务是从分布在地面环境中的 K∈N 固定物联网设备收集数据,设备 k∈[1, K] 的位置通过 uk∈N2 给出.每个设备都有一定量的数据 Dk(t)∈R 将由无人机收集。

所选设备 k 和无人机之间的数据吞吐量 Ck(t) 基于标准对数距离路径损耗模型,具有高斯阴影衰落,以及它们是否可以建立视距连接或被障碍物阻挡。

对数距离路径损耗模型是Friis自由空间模型的扩展。它被用来预测广泛的环境下的传播损失,而Friis自由空间模型被限制在发射机和接收机之间畅通无阻的路径。该模型包含了由于信号被山丘、树木、建筑物等遮挡而产生的随机阴影效应。它也被称为对数正态阴影模型。base
在这里插入图片描述
Friis自由空间模型
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

UAV 一次与一个设备进行通信,并选择具有剩余数据和可能的最高数据速率的设备。链路性能和多路访问协议的详细描述可以在 [2] 中找到。每个设备上的数据根据Dk (t + 1) = Dk (t) -Ck (t)

除了起始区和着陆区或内部障碍物外,设备可以位于每个单元格中。数据收集问题的目标是在最大飞行时间内收集尽可能多的设备数据

Unifying Map-Layer Description统一地图层描述

这两个问题都可以通过单个目标地图层 D(t)∈RM×M 来描述。在 CPP 中,目标地图层是通过根据 (1) 演化的 T(t) 给出的。在 DH 中,目标映射层显示了其中一个设备占用的每个单元格中的可用数据量,即位置 uk 处的单元格具有值 Dk(t),并根据 (2) 进行演变。
如果一个单元格不包含设备或设备数据已完全收集,则该单元格的值为 0。由于这两个问题可以用相似的状态表示来描述,因此都可以通过深度强化学习和具有相同状态的神经网络来解决结构体。

Methodology

方法可以直接应用于这两个不同的路径规划问题。

在大多数经典的 CPP 方法中,通过分割提取单个目标区域,然后将其与距离成本连接到一个图中,而每个段都覆盖有一个 boustrophedon 路径。这将 CPP 问题简化为旅行商问题 (TSP) 。

原则上,DH 问题也可以转换为 TSP,其中 IoT 设备作为图中的节点,设备之间的距离作为边成本。但是,转换忽略了与设备的通信发生在往返于设备之间的过程中。一般来说,DH问题中的最佳行为不是所有设备的顺序访问,因为数据已经可以通过从更远的地方建立LoS链路来有效收集,或者等待收集的大量数据可能需要无人机悬停长时间靠近设备。

这些约束与随机通信信道模型以及多路访问协议选择的各种可能性相结合,对于使用经典方法进行建模和求解而言并非易事。对于这两个问题,无人机电池限制为经典方法增加了另一个复杂性,因为完全覆盖或完全收集并不总是可行的。
以下 DRL 方法允许我们直接组合各个路径规划问题的所有目标和约束,而无需额外的近似。

A. Partially Observable Markov Decision Process

M 包含起始和着陆区、禁飞区和障碍物的环境地图;
D(t) 指示设备位置的剩余数据或在时间 t 未发现的剩余单元的目标图;
p(t) 无人机在时间 t 的位置;
b(t) 无人机在时间 t 的剩余移动预算;

可能的动作 A = {北、东、南、西、悬停、陆地},广义奖励函数 R(s(t), a(t), s(t+1)) 由以下元素组成

rc (positive) 数据收集或细胞覆盖奖励由收集的数据或新覆盖的目标细胞的数量,比较s(t+1)和s(t);
rsc(负)安全控制器(SC)惩罚,以防无人机与建筑物相撞或进入 NFZ;
rmov(负)恒定移动惩罚,适用于无人机在未完成任务的情况下采取的每项行动;
rcrash(负)惩罚,以防无人机的剩余飞行时间达到零而没有安全降落在着陆区。

B. Map Processing

将居中的地图呈现为两个输入:显示代理直接环境的全细节局部地图,显示整个环境的压缩全局地图(细节较少)。
下面给出三个函数的数学描述。图 1 显示了函数在数据管道中的使用位置。

    1. Map Centering
    1. Global-Local Mapping

C. Observation Space

在观测中,Ml(t) 和 Mg(t) 是环境的局部和全局观测值,Dl(t) 和 Dg(t) 分别是目标的局部和全局观测值。 b(t) 是无人机的剩余飞行时间,等于状态空间中的时间。
在这里插入图片描述

请注意,环境的局部和全局观测是时间相关的,因为它们以无人机的时间相关位置为中心。

通过将观察空间 Ω 输入代理而不是状态空间 S,问题被人为地转换为部分可观察的 MDP。部分可观测性是由局部地图的有限大小和全局地图的平均造成的。
通过以下结果,我们表明部分可观察性不会使问题对于无记忆代理不可行,并且压缩大大减小了神经网络的大小,显着减少了训练时间。

D. Double Deep Reinforcement Learning-Neural Network

用于两个 Q 网络的神经网络架构如图所示。
在这里插入图片描述

环境图和目标图堆叠并以无人机位置为中心,然后转换为全局和局部观测组件。
在分别通过两个卷积层后,得到的张量被展平并与剩余的飞行时间输入连接,并通过三个具有 ReLU 激活函数的隐藏层。
没有激活函数的输出层直接表示 Q 值,通过 softmax 函数创建用于探索的动作分布,或通过 argmax 函数 用于Q值的优化。

可伸缩性scalaer

有关可伸缩性的相关参数是扁平层的大小。它可以通过计算出来
在这里插入图片描述
nk为内核数,nc为卷积层数,sk为内核大小。将全局地图缩放参数设置为g=1,将局部地图大小设置为l=0,将停用全局-局部地图处理,即没有降采样,也没有额外的局部地图。评价中使用的参数如下。
在这里插入图片描述

每一对state-action

在这里插入图片描述

  • 为了收敛到最优的q值,代理探索环境,收集经验(s(t), a(t), r(t), s(t + 1)),存储到memory D,省略时间信息

使用了通过θ和θ¯参数化的两个Q网络

  • 其中一个q网络(基于memoryD的采样验证q值)通过最小化损失进行更新:
    在这里插入图片描述
  • 另一个网络的参数被更新为θ¯←(1−τ)θ¯+τθ,其软更新参数为τ∈(0,1]。

设置了组合经验重放

为了解决训练对重放记忆大小的敏感性,我们使用了Zhang和Sutton[16]提出的组合经验重放。

Simulations

A. Simulation Setup

无人机在两个不同的网格世界中飞行。
‘Manhattan32’ 场景(图 2a 和 2c)具有 32 × 32 个单元格,左上角和右下角有两个起始区和着陆区。除了规则的建筑模式外,还存在一些不规则形状的建筑和额外的 NFZ。
“Urban50”场景(图 2b 和 2d)包含 50 × 50 个单元和一个围绕中心建筑的起始和着陆区域。建筑物通常较大且间隔较大,地图底部还有一个额外的大型 NFZ。请注意,“Urban50”地图中的单元格数量大约比之前的作品 [1] 和 [2] 大一个数量级。场景的像元大小为 10m × 10m,表 II 提供了图例。

1) Coverage Path Planning

对于 CPP 问题,无人机以 25m 的恒定高度飞行,其下方安装了一个摄像头,视场角为 90°。因此,只要障碍物不阻挡视线,无人机可以同时覆盖 5 × 5 个单元的区域。目标区域是通过随机采样不同大小和类型的几何形状并叠加它们,创建部分连接的目标区域来生成的。

对于评估,CPP 问题的传统度量是路径长度。但是,该指标仅在可以进行全面覆盖时才提供有意义的比较。在这项工作中,我们研究了飞行时间受限的 CPP,其中通常不可能进行全面覆盖。因此,使用的评估指标是覆盖率(CR),即在剧集结束时覆盖的目标小区与初始目标小区的比率,以及覆盖率和着陆(CRAL),如果无人机没有,则为零如果成功着陆,则等于 CR。 CRAL 指标的好处在于它结合了两个目标,实现了高覆盖率并在飞行时间限制内返回着陆区。通过将性能标准化为 [0, 1] 中的值,它可以在变化的场景与随机生成的目标区域进行性能比较。

在这里插入图片描述
在这里插入图片描述

2) Data Harvesting

在 DH 问题中,无人机以 10m 的恒定高度飞行,与地面上的设备进行通信。可实现的数据速率是根据距离、随机阴影衰落和视距条件计算的,通信信道参数与 [2] 中使用的相同。与 CPP 一样,路径长度不是一个适用的度量。由于物联网设备的位置、数据量和最大飞行时间的随机变化,不可能在所有场景中收集所有数据。因此,使用的评估指标是收集率(CR),描述了从所有设备收集的数据与所有设备上的初始可用数据之和的比率。与 CPP 一样,我们也在此上下文中使用收集率和着陆 (CRAL),以一个标准化指标显示完整的数据采集和着陆性能。

B. General Evaluation

CPP 代理在包含 3-8 个形状的目标区域进行训练,覆盖 20-50% 的可用区域。 “Manhattan32”场景的移动范围设置为 50-150 步,“Urban50”场景的移动范围设置为 150-250。
对于 DH 场景,3-10 个设备随机放置在空闲单元中,包含 5.0-20.0 个数据单元。 “Manhattan32”场景的移动范围设置为 50-150 步,“Urban50”场景的移动范围设置为 100-200。详细评估了四个场景。

在 CPP 场景中,图 2a 和 2b 中的代理表明它们可以找到覆盖大部分目标区域的轨迹。甚至非关税区的区域也大多被覆盖。可以看出,需要绕行的小区域被忽略了,导致覆盖不完整。但是,大部分目标区域都被有效覆盖。

图 2c 和 2d 中 DH 场景中的代理表现非常好。在“Manhattan32”场景中,代理在橙色和紫色设备上留下少量数据,总计收集率为 99.1%。但是,代理找到了一条简洁的路径,只使用了允许的 150 个移动步骤中的 92 个。在“Urban50”场景中,代理设法收集所有数据并返回一些备用的移动步骤。

所有四个代理都接受了 200 万步的训练。在使用 1000 个蒙特卡洛生成的场景(见表 III)分析它们在所有四个任务中的性能时,可以看出所有代理的着陆性能都很好,“Urban50”DH 代理稍好一些。
在这里插入图片描述

C. Global-Local Parameter Evaluation

为了建立对新超参数、全局地图缩放 g 和局部地图大小 l 的性能敏感度,我们在 CPP 和 DH 问题上训练了多个具有不同参数的代理。我们为 l 选择了四个值,为 g 选择了四个值,并为每个可能的组合训练了三个代理。此外,我们在不使用全局和局部地图处理的情况下训练了三个智能体,这相当于设置 g=1 和 l=0。
生成的 51 个 CPP 和 DH 问题的代理分别接受了 500k 步的训练,并在 200 个 Monte Carlo 生成的场景上进行了评估。与之前评估的不同之处在于,移动预算范围设置为 150 – 300。

  • 使用不同的全局地图缩放和本地地图大小来扁平化“manhattan32”的图层大小;没有全局局部映射处理,大小为 48、401 个神经元。
    在这里插入图片描述

  • 相对于没有全局-局部地图处理的 cpp 和 dh 问题的训练时间加速。
    在这里插入图片描述

蒙特卡罗模拟得到的每个代理相对于代理的扁平层大小的 CRAL 值分别显示在 CPP 和 DH 问题的图 3a 和 3b 中。
可见DH问题比CPP问题对参数更敏感。通常,更大的展平层在一定程度上会产生更好的性能。对于这两个问题,可以看出大的扁平层会导致学习变得不稳定,导致某些运行的 CRAL 为零。
这是由于代理未能学习如何着陆造成的。不使用全局-局部地图方法的 DH 代理永远不会学习如何可靠地着陆,因此 CRAL 分数接近于零。
在这里插入图片描述

在这两种情况下,具有 l=17 和 g=3 或 g=5 的代理在其展平层大小方面表现出最佳性能,证明表 I 中的选择是合理的。
除了这两个参数组合之外,值得注意的是,具有l=9 和 g=7 在这两种情况下也表现良好,尽管它们的扁平层大小只有 33 个神经元。

Conclusion

我们提出了一种在两种截然不同的任务类型(覆盖路径规划和数据采集)上概括自主无人机路径规划的方法。通过在奖励函数中结合特定任务目标和导航约束所提供的灵活性,我们在两种场景中训练具有相同结构的 DDQN 以做出有效的运动决策。
我们引入了一种新颖的全局-局部地图处理方案,允许将大地图直接馈入 DRL 代理的卷积层,并分析地图处理参数对学习性能的影响。

  • 在未来的工作中,我们将调查将我们的方法应用于更大地图的仍然存在的障碍,即通过使用宏观行动或选项来避免小规模的决策交替[17]。
  • 将所提出的高级路径规划方法与低级飞行动力学控制器相结合,也将有可能在未来使用现实的开源无人机模拟器进行实验。
  • 此外,我们将研究不规则形状的非凸障碍物对路径规划性能的影响。

代码概览src

base-TSP

  • BaseDisplay.py

    create_grid_image[根据障碍物信息创建地图]
    draw_start_and_end[绘制最终点]
    draw_movement[绘制箭头]
    create_tf_image[某个画面具体的两幅图(图轨迹+直方图)]
    create_video

  • BaseGrid.py

    get_map_image、get_grid_size、get_no_fly、get_landing_zone

  • BaseState.py

    shape===landing_zone.shape[:2]

  • Environment.py

    fill_replay_memory[获取下一个状态]
    train_episode[获一个整个episode(下一步step\采样)]
    run[取多条episode进行验证保存最好的模型]
    step[获取下一个动作-状态-奖励]
    test_episode[验证episode的最终奖励]
    test_scenario[验证场景]
    init_episode[初始化----情况缓存列表]
    eval[在tqdm中随机采样(MC)episode评估模型,可选择是否绘图]
    eval_scenario[根据初始状态测试策略的选择过程]

  • GridActions.py

    北-东-南-西-着陆-盘旋:0,1,2,3,4,5

  • GridPhysics.py【物理可行—电量】

    movement_step[地图上更新xy,当前的电量,判断是否着陆]
    reset

  • GridRewards.py

    self.boundary_penalty = 1.0
    self.empty_battery_penalty = 150.0
    self.movement_penalty = 0.2
    calculate_motion_rewards[根据动作产生的状态与预计的差别给予惩罚]
    battery dead:next_state.movement_budget == 0 and not next_state.landed
    get_cumulative_reward、reset

DH

  • Channel.py【不同设备的电量和收集率,Los无障碍,或nLos有障碍】

    reset、get_max_rate
    compute_rate[计算某个设备与无人机直接的数据率]
    los规范因子×dis ^ los损失 × 10 ^ (los高斯/10)

  • DeviceManager.py

    generate_device_list[生成设备列表,准备设备的参数]
    generate_device_list_from_args[赋予设备具体参数(xy,数量,颜色)]

  • Display.py

    draw_bar_plots[绘制当前状态的直方图]
    display_episode[绘制整个轨迹的画面并保存,return create_tf_image]
    display_state[绘制状态 点图]

  • Environment.py

    DHEnvironmentParams(BaseEnvironmentParams)[init得到参数]
    DHEnvironment(BaseEnvironment)[初始化再看BaseEnvironment]

  • Grid.py

    init[获得地图的自由空间]
    get_comm_obstacles、get_data_map、get_collected_map
    get_device_list、get_grid_params、init_scenario
    init_episode[初始化设备列表并重置,获取状态,随机起点和耗电,更新电量]
    create_scenario[获取状态,并统计电量,设备位置,赋予设备信息]
    get_example_state[根据输入的地图获取状态]

  • IoTDevice.py

    class IoTDevice:针对单个点的动作
    DeviceList:针对所有点的动作
    get_data_map[统计每个节点剩余的数据量]
    get_collected_map[统计每个节点被收集的数据量]
    get_best_data_rate[得到最好数据率的设备序号]
    collect_data[收集某个序号的数据]
    get_devices、get_device、get_total_data、get_collected_data
    num_devices

  • Physice.py

    register_functions、reset
    step—comm_step[更新电量,数据率,收集情况-已收&剩余]
    get_example_action、is_in_landing_zone、get_movement_budget_used
    get_collection_ratio、get_max_rate
    get_boundary_counter、get_landing_attempts、has_landed
    get_average_data_rate=get_collected_data/get_movement_budget_used
    get_cral=get_collection_ratio*landed

  • Rewards.py

    calculate_reward[根据动作给予的惩罚+根据状态剩余数据的奖励]

  • State.py

    self.movement_budget = 100
    set_landed、set_position、decrement_movement_budget、set_terminal
    set_device_com、get_remaining_data、get_total_data
    get_scalars[总电量]、get_num_scalars
    get_boolean_map、get_boolean_map_shape
    get_float_map、get_float_map_shape
    is_in_landing_zone、is_in_no_fly_zone
    get_collection_ratio、get_collected_data、reset_devices、is_terminal

DDQN

  • Agent.py

    init[创建网络模型,定义目标函数,贝尔曼过程-loss,两个Q网络]
    build_model[创建基本流程的模型]
    create_map_proc[创建全局、局部地图]
    act[得到最大q值的动作]、get_random_action
    get_exploitation_action[从探索网络中获得最大q值的动作]
    get_soft_max_exploration[从软探索网络中获得最大q值的动作]
    get_exploitation_action_target[从目标网络中获得最大q值的动作]
    hard_update、soft_update
    train[与环境交互并采样验证,梯度上升]
    save_weights、save_model、load_weights
    get_global_map、get_local_map、get_total_map

  • Trainer.py

    init[采样轨迹]
    add_experience[将一条experience存储到经验池]
    train_agent[采样训练]
    should_fill_replay_memory[更新经验池的大小、判断是否更新目标网络]

  • ReplayMemory.py

    initialize、reset、shuffle
    store[存储experience到经验池]
    sample[获取batch_size大小进行采样]
    get[得到一条episode轨迹]
    get_size、get_max_size[得到轨迹的长短]

Map地图信息

  • Map.py

    get_starting_vector、get_free_space_vector、get_size
    load_image、save_image、load_map、load_target

  • Shadowing.py

    bresenham
    calculate_shadowing
    load_or_create_shadowing

ModelStats.py

add_experience[给轨迹加上最后一个状态和动作]
set_evaluation_value_callback、set_env_map_callback、set_model
add_log_data_callback
log_training_data、log_testing_data、log_data、get_log_dir
save_if_best、save_episode
training_ended、get_log_dir
on_episode_begin、on_episode_end

StateUtils.py

pad_centered[对全局地图压缩的手段,映射层被填充成0,1,1,0,只有禁飞和障碍]

测试信息

  • res:地图信息
  • main.py:训练

main_dh(params)

  • main_mc:蒙特卡洛训练,验证效果平均值

eval_logs
dh_mc(args, params)[Env-eval]展示路径的整个过程

  • main_scenario :

save_video
scenario[加载对应场景的模型进行评估和绘图]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在 C# 中使用依赖注入和反射可以通过实现一个依赖注入容器来实现。下面是一个简的示例: ```c# using System; using System.Collections.Generic; using System.Reflection; interface ICar { void Run(); } class BMW : ICar { public void Run() { Console.WriteLine("BMW is running"); } } class Audi : ICar { public void Run() { Console.WriteLine("Audi is running"); } } class Driver { private ICar car; public Driver(ICar car) { this.car = car; } public void RunCar() { car.Run(); } } class Container { private static Dictionary<Type, Type> types = new Dictionary<Type, Type>(); public static void Register<TType, TConcrete>() { types[typeof(TType)] = typeof(TConcrete); } public static object GetInstance(Type type) { if (types.ContainsKey(type)) { Type concreteType = types[type]; ConstructorInfo constructor = concreteType.GetConstructors()[0]; ParameterInfo[] parameters = constructor.GetParameters(); if (parameters.Length == 0) { return Activator.CreateInstance(concreteType); } else { List<object> parametersToPass = new List<object>(); foreach (ParameterInfo parameter in parameters) { parametersToPass.Add(GetInstance(parameter.ParameterType)); } return constructor.Invoke(parametersToPass.ToArray()); } } else { throw new Exception("Type not registered"); } } } class Program { static void Main(string[] args) { Container.Register<ICar, BMW>(); Container.Register<Driver, Driver>(); Driver driver = (Driver)Container.GetInstance(typeof(Driver)); driver.RunCar(); } } ``` 在上述示例中,我们定义了一个 `ICar` 接口和它的两个实现类 `BMW` 和 `Audi`,然后我们定义了一个司机类 `Driver`,它依赖于 `ICar` 接口。我们还定义了一个依赖注入容器类 `Container`,它使用反射

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值