你值得拥有.NET生态系统中那些优秀的依赖注入框架们
ccwgpt 2024-09-23 04:28 25 浏览 0 评论
在当今的软件开发世界中,依赖注入(Dependency Injection,DI)是一种常见的模式,用于降低代码之间的耦合度,提高可测试性和可维护性。依赖注入的主要目的是减少代码之间的耦合度,使得代码更容易测试和维护。通过将对象的依赖关系外部化,并将其存储在一个外部源中,依赖注入使得代码更容易替换和改变,而不会影响到其他部分的代码。此外,它还有助于实现代码的可测试性,因为可以在测试环境中轻松地模拟依赖项。在.NET生态系统中,依赖注入已经成为了核心的一部分,许多开发人员都使用它来构建高效、可扩展的应用程序。在本文中,我们将深入探讨.NET生态系统中的优秀依赖注入框架。它们各自具有独特的优点和适用场景。以下是其中一些:
Microsoft.Extensions.DependencyInjection
Microsoft.Extensions.DependencyInjection是一个在.NET平台上广泛使用的轻量级依赖注入框架,它是ASP.NET Core框架的一部分,并且也可以在其他.NET应用程序中使用。以下是它的一些优点和适用场景:
优点:
- 轻量级和易于使用:Microsoft.Extensions.DependencyInjection(简称DI)是一个轻量级的框架,使用简单,没有复杂的配置或学习曲线。它不需要任何第三方库或工具支持,已经内置在.NET Core和.NET标准中。
- 面向接口编程:DI框架鼓励面向接口编程,通过依赖注入接口来解耦组件之间的依赖关系。这样可以提高代码的可测试性、可维护性和可扩展性。
- 支持多种生命周期管理:DI框架提供了多种生命周期管理选项,如瞬时(Transient)、作用域(Scoped)和单例(Singleton)。这使得开发者可以根据需要配置服务的实例化方式和生命周期管理策略。
- 灵活的配置选项:DI框架通过简单的API提供了灵活的配置选项,开发者可以根据需求进行自定义配置。它支持构造函数注入、属性注入和方法注入等多种注入方式。
适用场景:
- ASP.NET Core应用程序:Microsoft.Extensions.DependencyInjection是ASP.NET Core框架的一部分,内置于ASP.NET Core中。它是构建Web应用程序或web API的首选依赖注入框架。
- .NET Core和.NET标准应用程序:DI框架可以在其他.NET Core和.NET标准应用程序中使用,不仅限于ASP.NET Core。无论是控制台应用程序、桌面应用程序还是类库项目,都可以受益于使用DI框架来管理组件之间的依赖关系。
- 小型和中型项目:DI框架适用于各种规模的项目,但在小型和中型项目中特别有优势。它提供了足够的灵活性和可配置性,同时又不会引入过多的复杂性。
案例说明:
// 定义接口
public interface ILogger
{
void Log(string message);
}
// 实现接口的类
public class ConsoleLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine(message);
}
}
using Microsoft.Extensions.DependencyInjection;
class Program
{
static void Main()
{
// 创建服务集合
var services = new ServiceCollection();
// 注册组件
services.AddSingleton<ILogger, ConsoleLogger>();
// 构建服务提供程序
var serviceProvider = services.BuildServiceProvider();
// 解析接口
var logger = serviceProvider.GetService<ILogger>();
// 使用解析得到的实例
logger.Log("Hello, Microsoft.Extensions.DependencyInjection!");
// 释放资源
if (serviceProvider is IDisposable disposable)
{
disposable.Dispose();
}
}
}
往期分享:ASP.NET Core依赖注入原理详解与Autofac库深度集成实践
Autofac
Autofac是一个流行的.NET平台上的依赖注入(DI)和反转控制(IoC)容器框架,它提供了丰富的功能和灵活的配置选项。以下是Autofac的一些优点和适用场景:
优点:
- 灵活的组件注册:Autofac提供了多种注册组件的方式,包括基于程序集的扫描注册、Lambda表达式注册、手动注册等。这使得开发者可以根据具体情况选择最合适的注册方式,并且能够满足复杂的注册需求。
- 生命周期管理:Autofac支持多种生命周期管理选项,包括实例化(Instance Per Dependency)、作用域(Instance Per Lifetime Scope)和单例(Single Instance)等。开发者可以根据需要灵活地配置组件的生命周期,确保依赖关系的正确管理。
- AOP集成:Autofac对面向切面编程(AOP)提供了良好的支持,可以轻松集成AOP框架,如Castle DynamicProxy,实现诸如日志记录、异常处理等横切关注点的统一处理。
- 模块化和组件化:Autofac支持模块化的组件注册方式,可以将相关的组件注册到单独的模块中,然后在应用程序启动时进行统一的加载和注册。这有助于提高代码的可维护性和可扩展性。
- 集成测试支持:Autofac对于集成测试提供了良好的支持,可以通过不同的注册方式来配置测试环境下所需的依赖关系,使得测试变得更加简单和灵活。
适用场景:
- 大型和复杂项目:Autofac适用于大型项目和复杂项目,特别是那些有着复杂依赖关系和组件互相调用的项目。通过Autofac的灵活注册和生命周期管理,可以更好地管理和解耦各个组件之间的依赖关系。
- 领域驱动设计(DDD):对于采用领域驱动设计的项目,Autofac提供了良好的支持。通过Autofac的模块化注册和灵活的配置,可以更好地组织和管理领域内的各种服务和工厂。
- Windows服务和后台任务:对于需要长期运行的Windows服务和后台任务,Autofac可以提供良好的依赖注入支持。它可以帮助管理服务、任务所需的各种依赖关系,并且有助于代码的模块化和单元测试。
- AOP需求较多的项目:如果项目中有较多的AOP需求,比如日志记录、性能监控、事务管理等方面,Autofac能够提供良好的支持,帮助将这些横切关注点与业务逻辑分离。
案例说明:
// 定义接口
public interface ILogger
{
void Log(string message);
}
// 实现接口的类
public class ConsoleLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine(message);
}
}
using Autofac;
class Program
{
static void Main()
{
// 创建容器构建器
var builder = new ContainerBuilder();
// 注册组件
builder.RegisterType<ConsoleLogger>().As<ILogger>();
// 构建容器
var container = builder.Build();
// 解析接口
var logger = container.Resolve<ILogger>();
// 使用解析得到的实例
logger.Log("Hello, Autofac!");
// 释放资源
container.Dispose();
}
}
往期分享:Autofac 是一个轻量级的依赖注入(DI)框架
Unity
Unity是一个功能丰富、灵活性强的依赖注入框架,适用于大型和复杂项目,特别是那些有着复杂依赖关系和AOP需求的项目。它可以帮助开发团队更好地管理和组织项目中的各种依赖关系,并且对于模块化和AOP集成有着显著的优势。以下是Unity框架的一些优点和适用场景:
优点:
- 简化依赖管理:Unity可以帮助开发者轻松管理和解耦组件之间的依赖关系。通过依赖注入,组件的依赖关系由容器负责管理和解析,使得组件之间的耦合度降低,代码更加灵活和可维护。
- 灵活的配置选项:Unity提供了多种配置选项,包括基于代码、XML配置文件、属性注解等方式来注册和配置组件。这使得开发者可以根据具体需求选择最合适的配置方式,并且能够满足复杂的注册需求。
- 生命周期管理:Unity支持多种生命周期管理选项,包括单例(Singleton)、瞬态(Transient)、分层(Per Resolve)等。开发者可以根据需要灵活地配置组件的生命周期,确保依赖关系的正确管理。
- AOP集成:Unity对面向切面编程(AOP)提供了良好的支持,可以轻松集成AOP框架,如Unity.Interception,实现诸如日志记录、异常处理等横切关注点的统一处理。
- 模块化和组件化:Unity支持模块化的组件注册方式,可以将相关的组件注册到单独的模块中,然后在应用程序启动时进行统一的加载和注册。这有助于提高代码的可维护性和可扩展性。
适用场景:
- 大型和复杂项目:Unity适用于大型项目和复杂项目,特别是那些有着复杂依赖关系和组件互相调用的项目。通过Unity的灵活注册和生命周期管理,可以更好地管理和解耦各个组件之间的依赖关系。
- ASP.NET Web应用程序:对于ASP.NET Web应用程序,Unity提供了良好的集成支持,并且能够与ASP.NET的生命周期无缝协同。通过Unity,可以轻松地管理Web应用程序中的各种服务和依赖关系。
- Windows服务和后台任务:对于需要长期运行的Windows服务和后台任务,Unity可以提供良好的依赖注入支持。它可以帮助管理服务、任务所需的各种依赖关系,并且有助于代码的模块化和单元测试。
- AOP需求较多的项目:如果项目中有较多的AOP需求,比如日志记录、性能监控、事务管理等方面,Unity能够提供良好的支持,帮助将这些横切关注点与业务逻辑分离。
案例说明:
// 定义接口
public interface ILogger
{
void Log(string message);
}
// 实现接口的类
public class ConsoleLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine(message);
}
}
using Unity;
class Program
{
static void Main()
{
// 创建容器
var container = new UnityContainer();
// 注册组件
container.RegisterType<ILogger, ConsoleLogger>();
// 解析接口
var logger = container.Resolve<ILogger>();
// 使用解析得到的实例
logger.Log("Hello, Unity!");
// 释放资源
container.Dispose();
}
}
DryIoc
DryIoc是一个轻量级的依赖注入(DI)容器框架,也是一个高性能、轻量级的依赖注入框架,适用于性能敏感的应用程序、微服务架构、跨平台开发、桌面和移动应用程序以及单元测试等场景。它的灵活性和配置选项使得开发者能够根据实际需求进行定制化配置,并且能够快速解决组件的依赖关系它为.NET平台提供了高性能和灵活的DI解决方案。以下是DryIoc框架的一些优点和适用场景:
优点:
- 1. 高性能:DryIoc以高性能著称,其快速的组件解析和依赖注入速度使得应用程序在运行时具有更好的性能表现。
- 2. 轻量级:DryIoc是一个轻量级的DI框架,它的核心库非常小巧,不会引入过多的额外依赖。
- 3. 灵活的配置选项:DryIoc提供了多种配置选项,包括基于代码、Lambda表达式、属性注解等方式来注册和配置组件。这使得开发者可以根据具体需求选择最合适的配置方式,并且能够满足复杂的注册需求。
- 4. 支持广泛的生命周期:DryIoc支持多种生命周期管理选项,包括单例(Singleton)、瞬态(Transient)、分层(Scoped)等。开发者可以根据需要灵活地配置组件的生命周期,确保依赖关系的正确管理。
- 5. AOP集成:DryIoc对面向切面编程(AOP)提供了良好的支持,可以轻松集成AOP框架,如AspectInjector,实现诸如日志记录、异常处理等横切关注点的统一处理。
适用场景:
- 1. 性能敏感的应用程序:由于DryIoc的高性能特点,它非常适用于对性能要求较高的应用程序。例如游戏引擎、大规模并发服务器等。
- 2. 微服务架构:在微服务架构中,每个微服务都可以使用自己独立的DI容器。DryIoc作为一个轻量级的DI框架,可以帮助构建和管理微服务之间的依赖关系。
- 3. 跨平台开发:DryIoc是一个跨平台的DI框架,可以在不同的.NET平台上使用,如.NET Framework、.NET Core、Xamarin等。这使得开发者可以在不同的平台上共享代码,并且无需更改DI容器的配置。
- 4. 桌面和移动应用程序:DryIoc适用于桌面和移动应用程序的开发,可以帮助解决组件之间的依赖关系,并提供灵活的配置选项。
- 5. 单元测试:DryIoc对于单元测试非常友好,它提供了轻松创建和管理依赖关系的功能,使得单元测试变得更加简单和可靠。
案例说明:
// 定义接口
public interface ILogger
{
void Log(string message);
}
// 实现接口的类
public class ConsoleLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine(message);
}
}
using DryIoc;
class Program
{
static void Main()
{
// 创建容器
var container = new Container();
// 注册组件
container.Register<ILogger, ConsoleLogger>();
// 解析接口
var logger = container.Resolve<ILogger>();
// 使用解析得到的实例
logger.Log("Hello, DryIoc!");
// 释放资源
container.Dispose();
}
}
Ninject
Ninject是一个在.NET平台上广泛使用的依赖注入(DI)框架,是一个易于使用、灵活而强大的依赖注入框架,适用于大型应用程序、模块化架构、单元测试、插件化开发以及跨平台开发等场景。它的简单性、灵活性和性能优化使得开发者能够轻松地解决组件之间的依赖关系,并提高代码的可维护性和可测试性。以下是Ninject框架的一些优点和适用场景:
优点:
- 1. 易于使用:Ninject提供了简洁明了的API和DSL(Domain Specific Language),使得配置和使用依赖注入变得非常简单。开发者可以通过一组简单的方法调用来注册和解析组件,减少了繁琐的手动构建对象和处理依赖关系的工作。
- 2. 灵活性:Ninject支持多种注册方式,包括基于代码、特性注解、配置文件等方式。开发者可以根据具体需求选择最合适的注册方式,并且能够满足复杂的注册需求。
- 3. 扩展性:Ninject提供了丰富的扩展点和插件机制,开发者可以通过自定义扩展来实现额外的功能和行为。这使得Ninject能够满足各种特定需求,并且与其他框架和工具无缝集成。
- 4. 交互性:Ninject支持通过属性注入、构造函数注入和方法注入等方式来解决组件之间的依赖关系。这使得开发者可以通过简单的声明来指定依赖关系,并且能够轻松地进行修改和替换。
- 5. 性能优化:Ninject对性能进行了优化,采用了一些技术手段来减少DI操作的开销。例如,Ninject使用了缓存和延迟初始化等策略,以提高解析组件的速度和效率。
适用场景:
- 1. 大型应用程序:Ninject适用于大型应用程序的开发,特别是需要管理复杂依赖关系的场景。通过使用Ninject,开发者可以轻松地组织和解决组件之间的依赖关系,提高代码的可维护性和可测试性。
- 2. 模块化架构:在模块化架构中,各个模块可以通过依赖注入来解耦和组合。Ninject提供了良好的支持,开发者可以使用Ninject来管理不同模块之间的依赖关系,实现模块的独立开发和部署。
- 3. 单元测试:Ninject对于单元测试非常友好,它可以帮助开发者轻松创建和管理依赖关系,使得单元测试变得更加简单和可靠。通过使用Ninject,开发者可以模拟和替换依赖组件,实现对被测对象的隔离测试。
- 4. 插件化开发:Ninject的灵活性和扩展性使得它非常适用于插件化开发。通过使用Ninject,开发者可以轻松地将不同的插件集成到应用程序中,并通过依赖注入来管理插件之间的依赖关系。
- 5. 跨平台开发:Ninject是一个跨平台的DI框架,可以在不同的.NET平台上使用,如.NET Framework、.NET Core、Xamarin等。这使得开发者可以在不同的平台上共享代码,并且无需更改DI容器的配置。
案例说明:
// 定义接口
public interface ILogger
{
void Log(string message);
}
// 实现接口的类
public class ConsoleLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine(message);
}
}
using Ninject;
class Program
{
static void Main()
{
// 创建内核
var kernel = new StandardKernel();
// 注册组件
kernel.Bind<ILogger>().To<ConsoleLogger>();
// 解析接口
var logger = kernel.Get<ILogger>();
// 使用解析得到的实例
logger.Log("Hello, Ninject!");
// 释放资源
kernel.Dispose();
}
}
Castle Windsor
Castle Windsor是一个成熟而强大的依赖注入(DI)框架,它可以帮助开发者管理和解决组件之间的依赖关系。Castle Windsor是一个易于使用、灵活而强大的依赖注入框架,适用于大型应用程序、模块化架构、插件化开发、跨平台开发以及可扩展的应用程序架构等场景。它的简单性、灵活性和可测试性使得开发者能够轻松地解决组件之间的依赖关系,并提高代码的可维护性和可靠性。以下是Castle Windsor框架的一些优点和适用场景:
优点:
- 1. 易于使用:Castle Windsor提供了简洁明了的API和配置方式,使得配置和使用依赖注入变得非常简单。开发者可以通过一组简单的方法调用、特性注解或配置文件来注册和解析组件,减少了手动构建对象和处理依赖关系的工作。
- 2. 灵活性:Castle Windsor支持多种注册方式,包括基于代码、特性注解、XML配置等方式。开发者可以根据具体需求选择最合适的注册方式,并且能够满足复杂的注册需求。
- 3. 扩展性:Castle Windsor提供了丰富的扩展点和插件机制,开发者可以通过自定义扩展来实现额外的功能和行为。这使得Castle Windsor能够满足各种特定需求,并且与其他框架和工具无缝集成。
- 4. 交互性:Castle Windsor支持通过属性注入、构造函数注入和方法注入等方式来解决组件之间的依赖关系。开发者可以通过简单的声明来指定依赖关系,并且能够轻松地进行修改和替换。
- 5. 可测试性:Castle Windsor支持对依赖关系进行模拟和替换,从而实现对被测对象的隔离测试。这使得开发者可以更加方便地编写单元测试和集成测试,并提高代码的可测试性和可靠性。
适用场景:
- 1. 大型应用程序:Castle Windsor适用于大型应用程序的开发,特别是需要管理复杂依赖关系的场景。通过使用Castle Windsor,开发者可以轻松地组织和解决组件之间的依赖关系,提高代码的可维护性和可测试性。
- 2. 模块化架构:在模块化架构中,各个模块可以通过依赖注入来解耦和组合。Castle Windsor提供了良好的支持,开发者可以使用Castle Windsor来管理不同模块之间的依赖关系,实现模块的独立开发和部署。
- 3. 插件化开发:Castle Windsor的灵活性和扩展性使得它非常适用于插件化开发。通过使用Castle Windsor,开发者可以轻松地将不同的插件集成到应用程序中,并通过依赖注入来管理插件之间的依赖关系。
- 4. 跨平台开发:Castle Windsor是一个跨平台的DI框架,可以在不同的.NET平台上使用,如.NET Framework、.NET Core、Xamarin等。这使得开发者可以在不同的平台上共享代码,并且无需更改DI容器的配置。
- 5. 可扩展的应用程序架构:Castle Windsor支持AOP(面向切面编程)和拦截器,开发者可以使用它来实现各种切面逻辑,如日志记录、性能统计、事务管理等。这使得开发者能够将关注点分离,并实现高度灵活和可扩展的应用程序架构。
案例说明
// 定义接口
public interface ILogger
{
void Log(string message);
}
// 实现接口的类
public class ConsoleLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine(message);
}
}
using Castle.MicroKernel.Registration;
using Castle.Windsor;
class Program
{
static void Main()
{
// 创建容器
var container = new WindsorContainer();
// 注册组件
container.Register(Component.For<ILogger>().ImplementedBy<ConsoleLogger>());
// 解析接口
var logger = container.Resolve<ILogger>();
// 使用解析得到的实例
logger.Log("Hello, Castle Windsor!");
// 释放资源
container.Release(logger);
}
}
部分框架测试结果对比
这些依赖注入框架都有自己独特的优势和特点,可以根据项目的需求和团队的熟悉程度来选择适合的框架。无论选择哪个框架,依赖注入都是提高代码可测试性、可维护性和可扩展性的重要工具,在.NET应用程序开发中起着关键作用。
相关推荐
- 定时任务工具,《此刻我要...》软件体验
-
之前果核给大家介绍过一款小众但实用的软件——小说规则下载器,可以把网页里的小说章节按照规则下载到本地,非常适合喜欢阅读小说的朋友。有意思的是,软件作者当时看到果核写的体验内容后,给反推荐到他的帖子里去...
- 前端定时任务的神库:Node-cron,让你的项目更高效!
-
在前端开发中,定时任务是一个常见的需求。无论是定时刷新数据、轮询接口,还是发送提醒,都需要一个可靠且灵活的定时任务解决方案。今天,我要向大家介绍一个强大的工具——Node-cron,它不仅能解决定时任...
- Shutter Pro!一款多功能定时执行任务工具
-
这是一款可以在电脑上定时执行多种任务的小工具,使用它可以根据时间,电量等来设定一些定时任务,像定时打开程序、打开文件,定时关机重启,以及定时弹窗提醒等都可以轻松做到。这是个即开即用的小工具,无需安装,...
- 深度解析 Redis 缓存击穿及解决方案
-
在当今互联网大厂的后端开发体系中,Redis缓存占据着极为关键的地位。其凭借高性能、丰富的数据类型以及原子性操作等显著优势,助力众多高并发系统从容应对海量用户的访问冲击,已然成为后端开发从业者不可或...
- 从零搭建体育比分网站完整步骤(比较好的体育比分软件)
-
搭建一个体育比分网站是一个涉及前端、后端、数据源、部署和维护的完整项目。以下是从零开始搭建的详细流程:一、明确项目需求1.功能需求:实时比分展示(如足球、篮球、网球等)支持多个联赛和赛事历史数据查询比...
- 告别复杂命令行:GoCron 图形界面让定时任务触手可及
-
如果你是运维人员或者经常接触一些定时任务的配置,那么你一定希望有一款图形界面来帮助你方便的轻松配置定时任务,而GoCron就是这样一款软件,让你的配置可视化。什么是GoCron从名字你就可以大概猜到,...
- Java任务管理框架核心技术解析与分布式高并发实战指南
-
在当今数字化时代,Java任务管理框架在众多应用场景中发挥着关键作用。随着业务规模的不断扩大,面对分布式高并发的复杂环境,掌握其核心技术并进行实战显得尤为重要。Java任务管理框架的核心技术涵盖多个方...
- 链表和结构体实现:MCU软件定时器(链表在单片机中的应用)
-
在一般的嵌入式产品设计中,介于成本、功耗等,所选型的MCU基本都是资源受限的,而里面的定时器的数量更是有限。在我们软件设计中往往有多种定时需求,例如脉冲输出、按键检测、LCD切屏延时等等,我们不可能...
- SpringBoot定时任务(springboot定时任务每小时执行一次)
-
前言在我们开发中,经常碰到在某个时间点去执行某些操作,而我们不能人为的干预执行,这个时候就需要我们使用定时任务去完成该任务,下面我们来介绍下载springBoot中定时任务实现的方式。定时任务实现方式...
- 定时任务新玩法!systemd timer 完整实战详解
-
原文链接:「链接」Hello,大家好啊!今天给大家带来一篇使用systemdtimer实现定时任务调度的详细实战文章。相比传统的crontab,systemdtimer更加现代化、结构清晰...
- Celery与Django:打造高效DevOps的定时任务与异步处理神器
-
本文详细介绍了Celery这一强大的异步任务队列系统,以及如何在Django框架中应用它来实现定时任务和异步处理,从而提高运维开发(DevOps)的效率和应用性能。下面我们先认识一下Cele...
- 订单超时自动取消的7种方案,我用这种!
-
前言在电商、外卖、票务等系统中,订单超时未支付自动取消是一个常见的需求。这个功能乍一看很简单,甚至很多初学者会觉得:"不就是加个定时器么?"但真到了实际工作中,细节的复杂程度往往会超...
- 裸机下多任务框架设计与实现(gd32裸机配置lwip 网络ping不通)
-
在嵌入式系统中,特别是在没有操作系统支持的裸机环境下,实现多任务执行是一个常见的挑战。本文将详细介绍一种基于定时器的多任务框架设计,通过全局时钟和状态机机制,实现任务的非阻塞调度,确保任务执行中不会出...
- 亿级高性能通知系统构建,小白也能拿来即用
-
作者介绍赵培龙,采货侠JAVA开发工程师分享概要一、服务划分二、系统设计1、首次消息发送2、重试消息发送三、稳定性的保障1、流量突增2、问题服务的资源隔离3、第三方服务的保护4、中间件的容错5、完善...
- 运维实战:深度拆解Systemd定时任务原理,90%的人不知道的玩法
-
运维实战:深度拆解Systemd定时任务原理,90%的人不知道的高效玩法一、Systemd定时任务的核心原理Systemd定时任务是Linux系统中替代传统cron的现代化解决方案,通过...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- MVC框架 (46)
- spring框架 (46)
- 框架图 (58)
- bootstrap框架 (43)
- flask框架 (53)
- quartz框架 (51)
- abp框架 (47)
- jpa框架 (47)
- laravel框架 (46)
- express框架 (43)
- springmvc框架 (49)
- 分布式事务框架 (65)
- scrapy框架 (56)
- shiro框架 (61)
- 定时任务框架 (56)
- grpc框架 (55)
- ppt框架 (48)
- 内联框架 (52)
- winform框架 (46)
- gui框架 (44)
- cad怎么画框架 (58)
- ps怎么画框架 (47)
- ssm框架实现登录注册 (49)
- oracle字符串长度 (48)
- oracle提交事务 (47)