返回顶部
首页 > 资讯 > 精选 >C#中怎么使用Unity实现IOC
  • 168
分享到

C#中怎么使用Unity实现IOC

2023-06-29 10:06:06 168人浏览 安东尼
摘要

这篇文章主要介绍“C#中怎么使用Unity实现ioc”,在日常操作中,相信很多人在C#中怎么使用Unity实现ioC问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C#中怎么使用Unity实现IOC”的疑惑有所

这篇文章主要介绍“C#中怎么使用Unity实现ioc”,在日常操作中,相信很多人在C#中怎么使用Unity实现ioC问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C#中怎么使用Unity实现IOC”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

一、什么是IOC

学习IOC之前先来了解一个依赖导致原则(DIP),依赖导致原则是IOC的核心原理。

依赖导致:即上层模块不应该依赖于低层模块,二者应该通过抽象来依赖。依赖于抽象,而不是依赖于细节。

首先来看下面的例子:

定义一个接口,封装数据库的基本CRUD操作,接口定义如下:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Data;namespace DataBase.Interface{    /// <summary>    /// 数据访问接口    /// </summary>   public  interface IDbInterface    {        string Insert();        string Delete();        string Update();        string Query();    }}

定义一个MSsql类实现该接口,用来模仿SQLServer操作,MSSQL类定义如下:

using DataBase.Interface;using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace DataBase.MSSQL{    public class DbMSSQL : IDbInterface    {        public string Delete()        {            return "MSSQL执行删除";        }        public string Insert()        {            return "MSSQL执行插入";        }        public string Query()        {            return "MSSQL执行查询";        }        public string Update()        {            return "MSSQL执行更新";        }    }}

定义一个oracle类实现该接口,模仿Oracle的操作,Oracle类定义如下:

using DataBase.Interface;using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace DataBase.Oracle{    public class DbOracle : IDbInterface    {        public string Delete()        {            return "Oracle执行删除";        }        public string Insert()        {            return "Oracle执行插入";        }        public string Query()        {            return "Oracle执行查询";        }        public string Update()        {            return "Oracle执行更新";        }    }}

定义一个控制台应用程序来调用:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using DataBase.Interface;using DataBase.MSSQL;namespace IOCConApp{    class Program    {        static void Main(string[] args)        {            // 常规做法,即程序的上端,依赖于下端,依赖于细节            DbMSSQL mssql = new DbMSSQL();        }    }}

常规做法是添加引用,然后直接实例化类,但是这样会依赖于细节实现,现将代码修改如下:

// 通过抽象来依赖IDbInterface dbInterface = new DbMSSQL();

但是这样修改以后,虽然左边是抽象了,但是右边还是依赖于细节。

那就究竟什么是IOC呢?

IOC(Inversion of Control)即控制反转,是一个重要的面向对象编程的法则来消减程序之间的耦合问题,把程序中上层对下层依赖,转移到一个第三方容器中来装配。IOC是程序设计的目标,实现方式包含依赖注入和依赖查找,在.net中只有依赖注入。

说到IOC,就不能不说DI。DI:即依赖注入,是IOC的实现手段。

二、使用Unity实现IOC

Unity是一个IoC容器,用来实现依赖注入(Dependency Injection,DI),减少耦合的,Unity出自于伟大的微软。

unity能够做什么呢,列举部分如下:

Unity支持简单对象创建,特别是分层对象结构和依赖,以简化程序代码。其包含一个编译那些可能存在依赖于其他对象的对象实例机制。
2.Unity支持必要的抽象,其允许开发者在运行时或配置去指定依赖关系同时可以简单的管理横切点(aop)。
3.Unity增加了推迟到容器组件配置的灵活性。其同样支持一个容器层次的结构。
4.Unity拥有服务定位能力,对于一个程序在许多情况下重复使用组件来分离和集中功能是非常有用的。
5.Unity允许客户端储存或缓存容器。对于在asp.net WEB applications中开发者将容器持久化于ASP.NET中的session或application中特别有效。
6.Unity拥有拦截能力,其允许开发者通过创建并执行handlers(在方法或属性被调用到达之前)来为已存在的组件增加一个函数,并再次为返回调用结果。
7.Unity可以从标准配置系统中读取配置信息,例如:XML文件,同时使用配置文件来配置容器。
8.Unity支持开发者实现自定义容器扩展,例如:你可以实现方法来允许额外的对象构造和容器特征,例如缓存。
9.Unity允许架构师和开发者在现代化的程序中更简单的实现通用设计模式

什么情况下要使用unity呢?

所构建的系统依赖于健全的面向对象原则,但是大量不同的代码交织在一起而难以维护。
2.构建的对象和类需要依赖其他对象或类。
3.依赖于复杂的或需要抽象的对象。
4.希望利用构造函数、方法或属性的调用注入优势。
5.希望管理对象实例的生命周期。
6.希望能够在运行时管理并改变依赖关系。
7.希望在拦截方法或属性调用的时候生成一个策略链或管道处理容器来实现横切(AOP)任务。
8.希望在Web Application中的回发操作时能够缓存或持久化依赖关系。

1、程序中安装Unity

使用管理NuGet程序包来安装Unity,在项目上右键,选择管理NuGet程序包:

C#中怎么使用Unity实现IOC

在搜索框里面输入Unity,点击右侧安装按钮进行安装:

C#中怎么使用Unity实现IOC

出现以下信息表示安装成功:

C#中怎么使用Unity实现IOC

2、使用Unity实现DI

先来看看最简单的Unity实现方式:

IUnityContainer container = new UnityContainer();//1、定义一个空容器container.ReGISterType<IDbInterface, DbMSSQL>();//2、注册类型,表示遇到IDbInterface的类型,创建DbMSSQL的实例var db = container.Resolve<IDbInterface>();Console.WriteLine(db.Insert());Console.ReadKey();

结果:

C#中怎么使用Unity实现IOC

从结果中可以看出,db是DbMSSQL类型的实例。

除了使用RegisterType注册类型以外,还可以注册一个实例,例如:

// 使用RegisterInstance注册IDbInterface的实例:new DbMSSQL() container.RegisterInstance<IDbInterface>(new DbMSSQL());

3、三种注入方式

三种注入方式:构造函数注入、属性注入、方法注入。

3.1 定义IHeadphone接口,代码如下:
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace DataBase.Interface{    public interface IHeadphone    {    }}
3.2 定义IMicrophone接口,代码如下:
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace DataBase.Interface{    public interface IMicrophone    {    }}
3.3 定义IPower接口,代码如下:
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace DataBase.Interface{    public interface IPower    {    }}
3.4 定义IPhone接口,代码如下:
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace DataBase.Interface{    public interface IPhone    {        void Call();        IMicrophone iMicrophone { get; set; }        IHeadphone iHeadphone { get; set; }        IPower iPower { get; set; }    }}
3.5 分别实现上面定义的接口

IPhone接口的实现如下:

using DataBase.Interface;using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using Unity.Attributes;namespace DataBase.MSSQL{    public class ApplePhone : IPhone    {        [Dependency]//属性注入        public IMicrophone iMicrophone { get; set; }        public IHeadphone iHeadphone { get; set; }        public IPower iPower { get; set; }        [InjectionConstructor]//构造函数注入        public ApplePhone(IHeadphone headphone)        {            this.iHeadphone = headphone;            Console.WriteLine("{0}带参数构造函数", this.GetType().Name);        }        public void Call()        {            Console.WriteLine("{0}打电话", this.GetType().Name); ;        }        [InjectionMethod]//方法注入        public void Init1234(IPower power)        {            this.iPower = power;        }    }}

IHeadphone接口的实现如下:

using DataBase.Interface;using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace DataBase.MSSQL{    public class Headphone : IHeadphone    {        public Headphone()        {            Console.WriteLine("Headphone 被构造");        }    }}

IMicrophone接口的实现如下:

using DataBase.Interface;using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace DataBase.MSSQL{    public class Microphone : IMicrophone    {        public Microphone()        {            Console.WriteLine("Microphone 被构造");        }    }}

IPower接口的实现如下:

using DataBase.Interface;using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace DataBase.MSSQL{    public class Power : IPower    {        public Power()        {            Console.WriteLine("Power 被构造");        }    }}

控制台程序调用:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using DataBase.Interface;using DataBase.MSSQL;using Unity;namespace IOCConApp{    /// <summary>    /// IOC():控制反转,把程序上层对下层的依赖,转移到第三方的容器来装配    ///          是程序设计的目标,实现方式包含了依赖注入和依赖查找(.net里面只有依赖注入)    /// DI:依赖注入,是IOC的实习方式。    /// </summary>    class Program    {        static void Main(string[] args)        {            #region MyRegion            //// 常规做法,即程序的上端,依赖于下端,依赖于细节            //DbMSSQL mssql = new DbMSSQL();            //// 通过抽象来依赖            //IDbInterface dbInterface = new DbMSSQL();            //IUnityContainer container = new UnityContainer();//1、定义一个空容器            //container.RegisterType<IDbInterface, DbMSSQL>();//2、注册类型,表示遇到IDbInterface的类型,创建DbMSSQL的实例            //var db = container.Resolve<IDbInterface>();            //// 使用RegisterInstance注册IDbInterface的实例:new DbMSSQL()            //container.RegisterInstance<IDbInterface>(new DbMSSQL());            //Console.WriteLine(db.Insert());            #endregion            IUnityContainer container = new UnityContainer();            container.RegisterType<IPhone, ApplePhone>();            container.RegisterType<IMicrophone, Microphone>();            container.RegisterType<IHeadphone, Headphone>();            container.RegisterType<IPower, Power>();            IPhone phone = container.Resolve<IPhone>();            Console.WriteLine($"phone.iHeadphone==null?  {phone.iHeadphone == null}");            Console.WriteLine($"phone.iMicrophone==null? {phone.iMicrophone == null}");            Console.WriteLine($"phone.iPower==null?      {phone.iPower == null}");            Console.ReadKey();        }    }}

输出结果:

C#中怎么使用Unity实现IOC

从输出结果中可以看出三种注入方式的执行顺序:先执行构造函数注入,在执行属性注入,最后执行方法注入。

注意:默认情况下如果构造函数上面没有使用特性,那么默认找参数最多的构造函数执行注入。

4、一个接口多个实现进行注册

如果多个不同的实例实现同一个接口,这种情况该怎么注册呢?先来看看下面的代码:

IUnityContainer container = new UnityContainer();//1、定义一个空容器container.RegisterType<IDbInterface, DbMSSQL>();//2、注册类型,表示遇到IDbInterface的类型,创建DbMSSQL的实例container.RegisterType<IDbInterface, DbOracle>();//表示遇到IDbInterface的类型,创建DbMSSQL的实例var db = container.Resolve<IDbInterface>();Console.WriteLine(db.Insert());

运行结果:

C#中怎么使用Unity实现IOC

从运行结果中可以看出,后面注册的类型会把前面注册的类型给覆盖掉,那么该如何解决呢?可以通过参数的方式来解决,代码如下:

IUnityContainer container = new UnityContainer();//1、定义一个空容器container.RegisterType<IDbInterface, DbMSSQL>("sql");//2、注册类型,表示遇到IDbInterface的类型,创建DbMSSQL的实例container.RegisterType<IDbInterface, DbOracle>("oracle");//表示遇到IDbInterface的类型,创建DbMSSQL的实例var sql = container.Resolve<IDbInterface>("sql");var oracle = container.Resolve<IDbInterface>("oracle");Console.WriteLine(sql.Insert());Console.WriteLine(oracle.Insert());

运行结果:

C#中怎么使用Unity实现IOC

5、生命周期

生命周期及一个对象从创建到释放中间经过的时间。先看下面的代码:

IUnityContainer container = new UnityContainer();container.RegisterType<IDbInterface, DbMSSQL>();IDbInterface db1 = container.Resolve<IDbInterface>();IDbInterface db2 = container.Resolve<IDbInterface>();Console.WriteLine("HashCode:"+db1.GetHashCode().ToString());Console.WriteLine("HashCode:" + db2.GetHashCode().ToString());Console.WriteLine(object.ReferenceEquals(db1,db2));

结果:

C#中怎么使用Unity实现IOC

表明db1和db2是两个不同的实例,即默认情况下生命周期是瞬时的,每次都是创建一个新的实例。

container.RegisterType<IDbInterface, DbMSSQL>(new TransientLifetimeManager());表示是瞬时生命周期,默认情况下即这种。

在看下面的代码:

IUnityContainer container = new UnityContainer();container.RegisterType<IDbInterface, DbMSSQL>(new ContainerControlledLifetimeManager());IDbInterface db1 = container.Resolve<IDbInterface>();IDbInterface db2 = container.Resolve<IDbInterface>();Console.WriteLine("HashCode:" + db1.GetHashCode().ToString());Console.WriteLine("HashCode:" + db2.GetHashCode().ToString());Console.WriteLine(object.ReferenceEquals(db1, db2));

结果:

C#中怎么使用Unity实现IOC

上图的结果可以看出,db1和db2是同一个实例。

container.RegisterType(new ContainerControlledLifetimeManager())表示是容器单例,每次都是同一个实例。

6、使用配置文件实现

在上面的例子中,所有的例子都是一直在依赖于细节,那么怎么解决不依赖于细节呢?答案是只能使用配置文件,配置文件如下:

<configuration>  <configSections>    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Unity.Configuration"/>  </configSections>  <unity>    <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Unity.Interception.Configuration"/>    <containers>      <container name="testContainer">        <!--逗号前面是接口类型的完全限定名:命名空间+接口名称,逗号后面是DLL文件的名称 name解决同一个接口不同实例问题-->        <register type="DataBase.Interface.IDbInterface,DataBase.Interface" mapTo="DataBase.MSSQL.DbMSSQL, DataBase.MSSQL" name="sql"/>        <register type="DataBase.Interface.IDbInterface,DataBase.Interface" mapTo="DataBase.Oracle.DbOracle, DataBase.Oracle" name="oracle"/>      </container>    </containers>  </unity></configuration>

注意:这个一个单独的配置文件,要把属性里面的复制到输出目录改为始终复制,那么这个配置文件才会生成到Debug目录里面。

程序如下:

ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "CfgFiles\\Unity.Config");//找配置文件的路径Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None); UnityConfigurationSection section = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName);IUnityContainer container = new UnityContainer();section.Configure(container, "testContainer");IDbInterface db = container.Resolve<IDbInterface>("sql"); Console.WriteLine(db.Insert());

结果:

C#中怎么使用Unity实现IOC

观察上面的代码,会发现,如果改成使用配置文件的方式实现的话,代码里面就不会依赖于细节了,只要一个接口类型。既然没有细节了,那么对项目进行如下的改造:把引用里面对细节的引用都去掉(即去掉DataBase.MSSQL和DataBase.Oracle),然后Debug文件夹里面没有这两个DLL了,但是这时需要把这两个DLL复制到Debug目录下面,否则程序运行的时候会找不到具体实现的类型。这样就意味着程序架构只依赖于接口。

C#中怎么使用Unity实现IOC

引用里面只要对接口的引用了,没有对具体实现的引用。去掉了对细节的依赖。

注意:使用配置文件实现时,必须把接口的具体实现类复制到程序目录下面。

如果有额外添加了一种数据库,那么只需要修改配置文件,把新的实现类复制到程序目录下面即可实现程序的升级。

使用配置文件的时候,需要把UnityContainer容器定义为静态的,这样只需要读取一次配置文件即可。

到此,关于“C#中怎么使用Unity实现IOC”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

--结束END--

本文标题: C#中怎么使用Unity实现IOC

本文链接: https://lsjlt.com/news/324285.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • C#中怎么使用Unity实现IOC
    这篇文章主要介绍“C#中怎么使用Unity实现IOC”,在日常操作中,相信很多人在C#中怎么使用Unity实现IOC问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C#中怎么使用Unity实现IOC”的疑惑有所...
    99+
    2023-06-29
  • C#使用Unity实现IOC
    一、什么是IOC 学习IOC之前先来了解一个依赖导致原则(DIP),依赖导致原则是IOC的核心原理。 依赖导致:即上层模块不应该依赖于低层模块,二者应该通过抽象来依赖。依赖于抽象,而...
    99+
    2024-04-02
  • 使用Unity怎么实现地面检测
    这篇文章将为大家详细讲解有关使用Unity怎么实现地面检测,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。1.普通射线在角色坐标(一般是脚底),发射一根向下的射线(长度约0.2)但是简单射线只...
    99+
    2023-06-15
  • Spring IoC中怎么实现依赖注入
    本篇文章为大家展示了Spring IoC中怎么实现依赖注入,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。一、依赖注入(DI)DI(Dependency Inject...
    99+
    2024-04-02
  • IOC使用Spring实现附实例详解
    目录 一、相关导读 1. Maven系列专栏文章 2. Mybatis系列专栏文章 3. Spring系列专栏文章 二、前言 Spring简介 Spring体系结构 三、Spring实现IOC 1. 创建Maven工程,引入对应依赖 2....
    99+
    2023-09-02
    java maven spring mybatis
  • c#使用Unity粒子实现炮塔发射系统
    目录一、进行粒子效果生成练习1、生成一个空项目2、创建一个粒子系统3、更改粒子系统参数4、Emission属性更改参数5、Shape属性更改参数6、发射管相关参数7、发射管粒子对象二...
    99+
    2024-04-02
  • Java中的IoC容器是怎么实现的
    本篇文章为大家展示了Java中的IoC容器是怎么实现的,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。IoC的概念介绍控制反转(IOC)模式(又称DI:Dependency Injection)就是I...
    99+
    2023-05-31
    java ioc ava
  • 使用unity怎么实现一个贪吃蛇游戏
    使用unity怎么实现一个贪吃蛇游戏?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。具体内容如下using UnityEngine;using UnityEn...
    99+
    2023-06-14
  • unity中的mvc框架怎么使用
    在Unity中使用MVC框架有多种方法,以下是一种常见的方式:1. 创建Model:在代码中创建一个数据模型类,用于存储游戏的数据和...
    99+
    2023-09-29
    unity
  • 使用Unity怎么实现一个虚拟键盘功能
    使用Unity怎么实现一个虚拟键盘功能?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。具体内容如下using UnityEngine;using System...
    99+
    2023-06-09
  • c#如何使用Unity粒子实现炮塔发射系统
    今天小编给大家分享一下c#如何使用Unity粒子实现炮塔发射系统的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。一、进行粒子效...
    99+
    2023-06-30
  • unity怎么调用c++动态库
    要在Unity中调用C++动态库,可以按照以下步骤进行操作:1. 创建C++动态库:首先,使用C++编写你的库,并将其编译为动态库(...
    99+
    2023-09-20
    unity c++
  • 如何使用TypeScript实现一个IoC容器
    这篇文章主要介绍“如何使用TypeScript实现一个IoC容器”,在日常操作中,相信很多人在如何使用TypeScript实现一个IoC容器问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何使用TypeScr...
    99+
    2023-06-16
  • SpringBoot实现使用反射模拟IOC和getBean
    IOC就是spring的核心思想之一:控制反转。这里不再赘述,看我的文章即可了解: spring基础思想IOC 其次就是java的反射,反射机制是spring的重要实现核心,今天我看...
    99+
    2023-05-14
    SpringBoot反射模拟IOC SpringBoot反射模拟getBean
  • 使用Spring.Net如何实现控制反转IoC
    今天就跟大家聊聊有关使用Spring.Net如何实现控制反转IoC,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。Spring.Net包括控制反转(IoC) 和面向切面(AOP)一、首...
    99+
    2023-05-31
    spring.net ioc
  • Unity使用LineRender实现签名效果
    本文为大家分享了Unity制作签名功能的具体代码,供大家参考,具体内容如下 前言:项目中需要做一个签名的功能,同时需要两个两个屏幕进行显示,但是都是在UI上,从网上查了大量资料。 找...
    99+
    2024-04-02
  • Unity中怎么利用ScrollView实现自动吸附效果
    Unity中怎么利用ScrollView实现自动吸附效果,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。通过使用UGUI的拖拽接口,在拖拽结束时比较当前滑动框的Normalize...
    99+
    2023-06-20
  • Unity怎么实现植物识别
    本篇内容介绍了“Unity怎么实现植物识别”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!接口介绍:可识别超过2万种常见植物和近8千种花卉,接...
    99+
    2023-06-22
  • Spring中利用IOC实现注入的方式
    目录1.环境搭建2.注入方式2.1.配置文件2.1.1.Set注入2.1.2.构造器注入2.2.注解注入3.获取方式4.Bean关系5.Bean生命周期6.Bean作用域1.环境搭建...
    99+
    2023-05-16
    Spring IOC注入 Spring注入方式
  • 怎么用Unity代码实现红酒识别
    这篇文章主要介绍“怎么用Unity代码实现红酒识别”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“怎么用Unity代码实现红酒识别”文章能帮助大家解决问题。接口介绍:识别图像中的红酒标签,返回红酒名称...
    99+
    2023-06-29
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作