企业级应用框架(五)IOC容器在框架中的应用

前言

  在上一篇我大致的介绍了这个系列所涉及到的知识点,在本篇我打算把IOC这一块单独提取出来讲,因为IOC容器在解除框架层与层之间的耦合有着不可磨灭的作用。当然在本系列前面的三篇中我也提供了一种基于反射的解耦方式,但是始终不是很优雅,运用到项目中显得别扭。目前,我所掌握的IOC容器主要有两个:一个是 unity,另一个则是spring.net,经过慎重的思考我还是决定选择unity 2.0做为本系列的IOC容器,原因主要有两个:第一,他是一个轻量级的容器且师出名门(微软),第二,它提供了简单的拦截机制,在它的基础上实现AOP显得非常的简单,下面开始我们今天的议题......

什么是IOC容器

  IOC容器是对控制反转与依赖注入的一种实现,关于什么是控制反转,什么是依赖注入,网上一搜一大把,我这里就不在多说了,我们需要关注的就是IOC容器到底能够为我们做些什么事情,其实说白了,IOC容器就是通过相应的配置,用来为我们创建实例,使我们摆脱了new的魔咒,这在层与层之间的解耦中有着重要的意义,至于层次间为什么要解耦请参见我的第一篇, 本文着重介绍unity 2.0,您需要在项目中添加对Microsoft.Practices.Unity.dll与Microsoft.Practices.Unity.Configuration.dll的引用,下面我通过简单doom来讲述它的运用,程序如图

IOC项目引用了IService项目,但并未引用service项目,IService项目中定义的是服务接口,Service项目引用了IService项目并实现了里面的服务接口。我们现在要做的事情就是在IOC中采用IService接口标识服务,在调用时采用unity容器读取配置文件帮助我们把接口实例化,其具体的服务来自Service项目(我们的IOC项目没有引用Service项目所以是无法new的),为了很好的运用Unity容器,我做了一下封装,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using System.Configuration;
using System.Reflection;namespace IOC
{public class ServiceLocator{/// <summary>/// IOC容器/// </summary>private readonly IUnityContainer container;private static readonly ServiceLocator instance = new ServiceLocator();/// <summary>/// 服务定位器单例/// </summary>public static ServiceLocator Instance{get { return instance; }}private ServiceLocator(){//读取容器配置文件UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");//创建容器container = new UnityContainer();//配置容器
            section.Configure(container);}#region   /// <summary>/// 创建构造函数参数/// </summary>/// <param name="overridedArguments"></param>/// <returns></returns>private IEnumerable<ParameterOverride> GetParameterOverrides(object overridedArguments){List<ParameterOverride> overrides = new List<ParameterOverride>();Type argumentsType = overridedArguments.GetType();argumentsType.GetProperties(BindingFlags.Public | BindingFlags.Instance).ToList().ForEach(property =>{var propertyValue = property.GetValue(overridedArguments, null);var propertyName = property.Name;overrides.Add(new ParameterOverride(propertyName, propertyValue));});return overrides;}#endregion#region 公共方法/// <summary>/// 创建指定类型的容器/// </summary>/// <typeparam name="T"></typeparam>/// <returns></returns>public T GetService<T>(){return container.Resolve<T>();}/// <summary>/// 根据指定名称的注册类型/// 创建指定的类型/// </summary>/// <typeparam name="T"></typeparam>/// <param name="name">注册类型配置节点名称</param>/// <returns></returns>public T GetService<T>(string name){return container.Resolve<T>(name);}/// <summary>/// 用指定的构造函数参数/// 创建实体/// </summary>/// <typeparam name="T">实体类型</typeparam>/// <param name="overridedArguments">属性名对应参数名,属性值对应/// 参数值得动态参数实体</param>/// <returns></returns>public T GetService<T>(object overridedArguments){var overrides = GetParameterOverrides(overridedArguments);return container.Resolve<T>(overrides.ToArray());}/// <summary>/// /// </summary>/// <typeparam name="T"></typeparam>/// <param name="name"></param>/// <param name="overridedArguments"></param>/// <returns></returns>public T GetService<T>(string name,object overridedArguments){var overrides = GetParameterOverrides(overridedArguments);return container.Resolve<T>(name, overrides.ToArray());}#endregion}
}
View Code

好了,下面开始我们的测试,我们首先在IService项目创建一个ISayHello服务接口代码如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace IService
{public interface ISayHello{string hello();}
}
View Code

下面我们在Service项目中创建一个ChineseSayHello服务实现ISayHello接口代码如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using IService;namespace Service
{public class ChineseSayHello : ISayHello{public string hello(){return "你好";}}
}
View Code

下面我们创建一个测试页面Test.aspx,后台代码如下

using IService;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;namespace IOC
{public partial class Test : System.Web.UI.Page{protected void Page_Load(object sender, EventArgs e){ISayHello sayhello = ServiceLocator.Instance.GetService<ISayHello>();showInfo.InnerText = sayhello.hello();}}
}
View Code

好,下面来看一看我们的配置文件

<?xml version="1.0" encoding="utf-8"?><!--有关如何配置 ASP.NET 应用程序的详细消息,请访问http://go.microsoft.com/fwlink/?LinkId=169433-->
<configuration><configSections><section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/></configSections><unity xmlns="http://schemas.microsoft.com/practices/2010/unity"><container><register  type="IService.ISayHello,IService"  mapTo="Service.ChineseSayHello,Service"></register></container></unity><system.web><compilation debug="true" targetFramework="4.0" /></system.web>
</configuration>

<register/>节点是告诉容器我要向容器中注册一个ISayHello接口类型,并且当每次要创建的ISayHello类型的时候都映射到ChineseSayHello实例。我们执行程序,得到的结果为:你好,这说明我们的容器正确的为我们创建ChineseSayHello实例。如果有一天我们觉得ChineseSayHello不好,我们想换一个服务来实现ISayHello,比如:EnglishSayHello,从而替代ChineseSayHello,我们仅需要创建一个EnglishSayHello类型,修改下配置文件,如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using IService;namespace Service
{public class EnglishSayHello : ISayHello{public string hello(){return "hello";}}
}
View Code
<?xml version="1.0" encoding="utf-8"?><!--有关如何配置 ASP.NET 应用程序的详细消息,请访问http://go.microsoft.com/fwlink/?LinkId=169433-->
<configuration><configSections><section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/></configSections><unity xmlns="http://schemas.microsoft.com/practices/2010/unity"><container><!--<register  type="IService.ISayHello,IService"  mapTo="Service.ChineseSayHello,Service"></register>--><register  type="IService.ISayHello,IService"  mapTo="Service.EnglishSayHello,Service"></register></container></unity><system.web><compilation debug="true" targetFramework="4.0" /></system.web>
</configuration>
View Code

程序的运行结果为:hello,实例创建成功。简简单单的一个例证,我们看见了IOC容器在给我们带来的巨大好处,我们IOC层根本不再依赖于具体的服务,我们想要什么实例配置下文件即可,这样极大的增加了程序的灵活性与可扩张性.

    下面,我们来讨论一下容器实例的生命周期,也就是实例在容器中的存活时间。举个例子,我们在同样的配置文件下连续创建多个ISayHello服务实例,很显然,这样的多个实例是来自同样的类型的,现在我们关心的是容器是每一次都会为我们创建该类型的实例,还是仅仅只为我们创建一个,以后所有的ISayHello都引用同一个实例呢?我们测试下,代码如下

using IService;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;namespace IOC
{public partial class Test : System.Web.UI.Page{protected void Page_Load(object sender, EventArgs e){ISayHello sayhello = ServiceLocator.Instance.GetService<ISayHello>();ISayHello sayhello1 = ServiceLocator.Instance.GetService<ISayHello>();showInfo.InnerText = sayhello.GetHashCode().Equals(sayhello1.GetHashCode()).ToString();}}
}
View Code

我们得到的结果是False,很显然容器每次都为我们去创建了一个实例。事实上Unity容器创建实例的机制是这样的:首先去容器中查找有没有这样的实例还保持在容器中,如果有的话则直接拿出来,如果没有的话则重新去创建一个。现在关键的问题是容器采用什么用的机制去保存这些被创建出来的实例,也就是实例在容器中的生命周期,在默认的情况下,实例被创建出来,容器即不再保存该实例,故在下次创建的时候容器找不到这样的实例,从而重新创建该类型实例,事实上实例的生命周期是可以配置的,我们甚至可以自定义实例的生命周期,下面我们修改下配置文件,设置实例的lifetime类型为singleton,即让实例永远保持在容器中,如下

<?xml version="1.0" encoding="utf-8"?><!--有关如何配置 ASP.NET 应用程序的详细消息,请访问http://go.microsoft.com/fwlink/?LinkId=169433-->
<configuration><configSections><section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/></configSections><unity xmlns="http://schemas.microsoft.com/practices/2010/unity"><container><!--<register  type="IService.ISayHello,IService"  mapTo="Service.ChineseSayHello,Service"></register>--><register  type="IService.ISayHello,IService"  mapTo="Service.EnglishSayHello,Service"><lifetime type="singleton"/></register></container></unity><system.web><compilation debug="true" targetFramework="4.0" /></system.web>
</configuration>
View Code

我们在运行程序,得到的结果是:True,说明我们每次都引用了同一个实例,容器很好的帮我们实现了单例模式,除了singleton外,容器还默认了其他的几种实例生命周期,这里就不在多说了。注:我们所说的实例生命周期不是指实例的创建到销毁,而是指实例在容器中创建,受容器管辖的时间范围。

    Unity容器支持为一个接口或者基类注册多个映射节点,但是每个节点需要采用不同的名称标识,在创建实例的时候,也通过该节点名称来创建指定的映射实例,例如

<?xml version="1.0" encoding="utf-8"?><!--有关如何配置 ASP.NET 应用程序的详细消息,请访问http://go.microsoft.com/fwlink/?LinkId=169433-->
<configuration><configSections><section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/></configSections><unity xmlns="http://schemas.microsoft.com/practices/2010/unity"><container><register   type="IService.ISayHello,IService"  mapTo="Service.ChineseSayHello,Service"></register><register name="english" type="IService.ISayHello,IService"  mapTo="Service.EnglishSayHello,Service"></register></container></unity><system.web><compilation debug="true" targetFramework="4.0" /></system.web>
</configuration>
View Code
using IService;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;namespace IOC
{public partial class Test : System.Web.UI.Page{protected void Page_Load(object sender, EventArgs e){ISayHello sayhello = ServiceLocator.Instance.GetService<ISayHello>();ISayHello sayhello1 = ServiceLocator.Instance.GetService<ISayHello>("english");showInfo.InnerText = string.Format("{0}+{1}", sayhello1.hello(), sayhello.hello());//showInfo.InnerText = sayhello.GetHashCode().Equals(sayhello1.GetHashCode()).ToString();
        }}
}
View Code

结果为:hello+你好,我们成功的通过了配置文件中的注册节点名称来创建我们的具体服务实例。我们知道创建实例是需要调用实例的构造函数的,很显然容器默认的为我们调用了构造函数,倘若构造函数带有参数,则容器则会创建相应的参数实例。现在问题来了,假如我的参数是一个接口或者抽象类型怎么办? 很显然要能创建这样的参数我们就必须知道参数的映射类型, 看如下例子,我们在IService项目中重新创建一个接口

using System;
using System.Collections.Generic;
using System.Linq; using System.Text; namespace IService { public interface ISay { string Say(); } }
View Code

我们写一个服务实现该接口

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using IService;namespace Service
{public class ComSayHello_V2 : ISay{public ISayHello Chinese { get; set; }public ComSayHello_V2(ISayHello chinese){this.Chinese = chinese;}public string Say(){return this.Chinese.hello();}}
}
View Code

配置文件如下

<?xml version="1.0" encoding="utf-8"?><!--有关如何配置 ASP.NET 应用程序的详细消息,请访问http://go.microsoft.com/fwlink/?LinkId=169433-->
<configuration><configSections><section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/></configSections><unity xmlns="http://schemas.microsoft.com/practices/2010/unity"><container><register   type="IService.ISayHello,IService"  mapTo="Service.ChineseSayHello,Service"></register><register name="english" type="IService.ISayHello,IService"  mapTo="Service.EnglishSayHello,Service"></register><register  type="IService.ISay,IService"  mapTo="Service.ComSayHello_V2,Service"></register></container></unity><system.web><compilation debug="true" targetFramework="4.0" /></system.web>
</configuration>
View Code
using IService;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;namespace IOC
{public partial class Test : System.Web.UI.Page{protected void Page_Load(object sender, EventArgs e){//ISayHello sayhello = ServiceLocator.Instance.GetService<ISayHello>();//ISayHello sayhello1 = ServiceLocator.Instance.GetService<ISayHello>("english");//showInfo.InnerText = string.Format("{0}+{1}", sayhello1.hello(), sayhello.hello());//showInfo.InnerText = sayhello.GetHashCode().Equals(sayhello1.GetHashCode()).ToString();ISay say = ServiceLocator.Instance.GetService<ISay>();showInfo.InnerText=say.Say();}}
}
View Code

我们得到结果:你好。在配置文件中我们添加了两个注册节点,从结果中我们看见,容器默认选择了未命名的节点,倘若我们注释该节点程序将报错,程序没办法自动识别带名称的节点,要想让程序识别带名称的节点我们需要配置构造函数参数,配置如下

<?xml version="1.0" encoding="utf-8"?><!--有关如何配置 ASP.NET 应用程序的详细消息,请访问http://go.microsoft.com/fwlink/?LinkId=169433-->
<configuration><configSections><section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/></configSections><unity xmlns="http://schemas.microsoft.com/practices/2010/unity"><container><!--<register   type="IService.ISayHello,IService"  mapTo="Service.ChineseSayHello,Service"></register>--><register name="english" type="IService.ISayHello,IService"  mapTo="Service.EnglishSayHello,Service"><!--<lifetime type="singleton"/>--></register><register  type="IService.ISay,IService"  mapTo="Service.ComSayHello_V2,Service"><constructor><param name="say" dependencyName="english"></param></constructor></register></container></unity><system.web><compilation debug="true" targetFramework="4.0" /></system.web>
</configuration>
View Code

结果正确的显示为:hello,在这里顺便提一下如果我们取消english注册节点lifetime的注释,我们会发现每次创建ComSayHello_V2的参数将来自同一个实例的引用,原因请参见,上文的实例生命周期。
    当然我们也可以直接在配置文件的构造函数中指定,参数类型而避免注册其他类型节点,配置文件代码如下,结果一样

<?xml version="1.0" encoding="utf-8"?><!--有关如何配置 ASP.NET 应用程序的详细消息,请访问http://go.microsoft.com/fwlink/?LinkId=169433-->
<configuration><configSections><section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/></configSections><unity xmlns="http://schemas.microsoft.com/practices/2010/unity"><container><register  type="IService.ISay,IService"  mapTo="Service.ComSayHello_V2,Service"><constructor><param  name="say" dependencyType="Service.EnglishSayHello,Service"></param></constructor></register></container></unity><system.web><compilation debug="true" targetFramework="4.0" /></system.web>
</configuration>
View Code

    其实,我们还能够在配置文件中给参数赋值,但是如果参数是一个复杂类型,比如类的时候,我们就需要一个转换器,把字符串类型的值转换为指定的赋值类型,因为在配置文件中我们赋值的类型只能是string。转换器在平时实践中用的少,所以我不打算多说。需要注意的是,如果我们的类中有多个构造函数的话,那么容器默认总会选择参数最多的那个构造函数。
   以上所介绍的归根到底也只是一种构造函数注入。其实Unity还提供能属性注入与方法注入,即在创建实例的时候动态为某个属性赋值或者调用某个方法,其实这个要做到也蛮简单的,我们只需要在相应的属性上面打上[Dependency]特性,在方法上打上[InjectionMethod]特性即可,但是这两种方式对类的侵入性太强,不推荐使用

总结

    本文简单的演示了Unity IOC的一些使用方法,因为在我的框架中,Unity在层次解耦中充当了重要的作用,除此之外Unity其实还能实现的AOP拦截,但是由于篇幅的原因不再多讲,在这里要提醒大家务必理解实体的生命周期,因为这对实现单元工作模式有着重要的意义。在我的系列前三篇中,我都是采用了是反射来解耦,有兴趣的朋友可以尝试下用Unity取代它。我目前写的案例与前面系列的版本框架有很大的差异,所以有些知识点必须和大家说明,相信在接下来的一到两篇中,就能与大伙见面,祝大伙周末愉快。本篇测试源码请点击这里

 

转载于:https://www.cnblogs.com/shaoshun/p/3868968.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/260197.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

后端开发需要学什么_都2020年了,还在纠结学什么语言?| 后端篇

几个礼拜前&#xff0c;一个学弟问我&#xff1a;“Ray&#xff0c;我打算之后要找工作了&#xff0c;不过现在自己没有特别深入的语言&#xff0c;最近想找一门好好学一下&#xff0c;你觉得学什么语言好呀&#xff1f;”我表示&#xff1a;“这个要看你求职方向、个人喜好、市…

python扫描ip的端口打开情况

我们的韩国bss系统上线之后&#xff0c;要求对主机的端口、资源使用进行统计&#xff0c;端口每个主机去看&#xff0c;太费劲了&#xff0c;所以&#xff0c;就写了这样一个小程序&#xff0c;不是很完美但是&#xff0c;可以用啊&#xff01;哈哈哈&#xff0c;别喷&#xff…

flash java 通信,Flash到JavaScript的通信实例

从HTML可以发送数据到Flash,反过来也可以. 这个例子演示了如何应用Flash的Fscommand来发送数据到Javascript.简要步骤:Flash中新建一个文件,保存为flash_to_javascript.fla创建一个文本域,设置成输入文本(Input Text),选择"border"以便我们能看到他,指定他的变量为in…

10个非常有用的CSS hack和技术

转自&#xff1a;http://www.qianduan.net/10-useful-css-hacks-and-technique.html 1 – 跨浏览器的inline-block <style>li {width: 200px;min-height: 250px;border: 1px solid #000;display: -moz-inline-stack;display: inline-block;margin: 5px;zoom: 1;*display:…

Java的递归算法

递归算法设计的基本思想是&#xff1a;对于一个复杂的问题&#xff0c;把原问题分解为若干个相对简单类同的子问题&#xff0c;继续下去直到子问题简单到可以直接求解&#xff0c;也就是说到了递推的出口&#xff0c;这样原问题就有递推得解。 关键要抓住的是&#xff1a; &…

python list遍历定位元素_python for循环,第二遍定位不到元素?

ycyzharry: 也不行&#xff0c;我的代码import unittestimport timeimport xlrdfrom selenium import webdriverimport seleniumdef open_excel(filefile.xls):try:data xlrd.open_workbook(file)return dataexcept Exception as e:print(str(e))def excel_table_byindex(file…

发现Java程序中的Bug

昨天在CSDN上阅读 "Java中十个常见的违规编码"这篇文章时&#xff0c;无意中找到了3个 "发现Java程序中的Bug"工具。 文章地址&#xff1a;http://www.csdn.net/article/2012-09-11/2809829-common-code-violations-in-java其中&#xff0c; FindBugs™ - …

原生php登录注册,原生php登陆注册

本以为一个登陆注册功能十来分钟就写好了&#xff0c;没想到thinkPHP用久了&#xff0c;原生的php不会写了最开始我直接写了类和方法&#xff0c;在前台传递参数给类的login方法(action"index.php/login"),尝试几次发现无法访问&#xff0c;这才意识到&#xff0c;这…

SpringMVC REST 风格静态资源访问配置

1 在web.xml中使用默认servlet处理静态资源&#xff0c;缺点是如果静态资源过多&#xff0c;则配置量会比较大&#xff0c;一旦有遗漏&#xff0c;则会造成资源无法正常显示或404错误。 <!-- 静态资源访问控制 --><servlet-mapping><servlet-name>default<…

生成对象

var c[name,age,city]; var d[xiaogang,12,anhui]; var a{}; for(var i0;i<3;i){a[c[i]]d[i]; } console.log(a); //返回 {name: "xiaogang", age: "12", city: "anhui"} 转载于:https://www.cnblogs.com/xiaozhumaopao/p/6046823.html

3.寄存器(内存访问)

CPU中&#xff0c;用16位来存储一个字。高8位存放高位字节&#xff0c;低8位存放低位字节。内存存储中&#xff0c;内存单元是字节单元&#xff08;1单元1字节&#xff09;&#xff0c;则一个字要用两个地址连续的内存单元存放。内存存储中&#xff0c;高位字节&#xff0c;和低…

shiro前后端分离_为什么要前后端分离?前后端分离的优点是什么?

随着互联网的高速发展以及IT开发技术的升级&#xff0c;前后端分离已成为互联网项目开发的业界标准使用方式。在实际工作中&#xff0c;前后端的接口联调对接工作量占HTML5大前端人员日常工作的30%-50%&#xff0c;甚至会更高。接下来千锋小编分享的广州HTML5大前端学习就给大家…

POJ 2152 Fire

算是我的第一个树形DP 的题&#xff1a; 题目意思&#xff1a;N个城市形成树状结构。现在建立一些消防站在某些城市&#xff1b;每个城市有两个树形cost&#xff08;在这个城市建立消防站的花费&#xff09;&#xff0c;limit &#xff1b; 我们要是每个城镇都是安全的&#xf…

php 解析HTTP协议六种请求方法,get,head,put,delete,post有什么区别

GET&#xff1a; 请求指定的页面信息&#xff0c;并返回实体主体。HEAD&#xff1a; 只请求页面的首部。POST&#xff1a; 请求服务器接受所指定的文档作为对所标识的URI的新的从属实体。PUT&#xff1a; 从客户端向服务器传送的数据取代指定的文档的内容。DELETE&#xff1a; …

python的socket连接不上_Python套接字只允许一个连接,但在新的连接上断开,而不是拒绝...

我不确定我完全理解你的问题&#xff0c;但我认为下面的例子可以满足你的要求。服务器可以断开旧用户的连接&#xff0c;为新用户提供服务。在服务器端&#xff1a;#!/usr/bin/env pythonimport socketimport multiprocessingHOST 127.0.0.1PORT 50007# you can do your real…

dede搜索php在哪,dede搜索页面怎么调用及相关搜索调用

dede搜索页面怎么调用&#xff0c;那几天有事情&#xff0c;所以导致博客几天都一直没有更新&#xff0c;之前我们讲过dede内容页面和dede列表模板的调用&#xff0c;今天我们一起来学习下搜索页面的调用&#xff0c;很多做企业站朋友们都不知道dede的搜索页怎么仿&#xff0c;…

电脑中病毒后被隐藏的文件的显示

用批处理或DOS更改属性。批处理就是建个记事本&#xff0c;输入attrib -h -s -r %~dp0\*.* /s /d&#xff0c;然后另存为随便.bat&#xff0c;把它放到那些隐藏文件夹外面&#xff08;不是里面&#xff09;&#xff0c;然后双击打开&#xff0c;等它自己关闭窗口就好了转载于:h…

HDU 3555 - Bomb

第一道数位dp&#xff0c;属于基础模板&#xff0c;又自卑小时没学好数数了&#xff0c;只是不清楚为什么大家的dp定义都是相同的&#xff0c;很显然么&#xff0c;难道我写的是怪胎。。。 /* ID:esxgx1 LANG:C PROG:hdu3555 */ #include <cstdio> #include <cstring&…

浏览器angent分析工具

cz.mallat.uasparser.UserAgentInfo info null; info uasParser.parse(userAgent);转载于:https://www.cnblogs.com/yaohaitao/p/6048011.html

python2协程_python中的协程(二)

协程1、协程&#xff1a;单线程实现并发在应用程序里控制多个任务的切换保存状态优点&#xff1a;应用程序级别速度要远远高于操作系统的切换缺点&#xff1a;多个任务一旦有一个阻塞没有切&#xff0c;整个线程都阻塞在原地&#xff0c;该线程内的其他的任务都不能执行了一旦引…