ASP.NET MVC IOC之Unity攻略
ASP.NET MVC IOC之Unity攻略
一、你知道IOC与DI吗?
1、IOC(Inversion of Control )——控制反转
即依赖对象不在被依赖模块的类中直接通过new来获取
先看看下面这段代码的问题~

public class SqlServerDal
{
public void Delete()
{
Console.WriteLine("删除表中某个订单信息!");
}
} public class Order
{
private readonly SqlServerDal dal = new SqlServerDal();
public void Delete()
{
dal.Delete();
}
} using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DIPTest
{
class Program
{
static void Main(string[] args)
{
Order order = new Order();
order.Delete();
Console.Read();
}
}
}

关于以上例子的说明:
(1)在Order类中,它依赖于具体的对象SqlServerDal,违反了依赖倒置的原则,即不论是高层还是底层,都应该依赖于抽象而不应该依赖于具体
(2)如果需求有变:数据访问层换为OracleDal,那么这个时候,就要修改Order类的代码;如果数据访问层再次换为MySqlDal,那么还要继续修改Order类的代码......如果无休止的变下去,将会是一个噩梦,而且你不但要修改 Order里边的代码,可能你还要修改Product、Users等类里边的代码,因为它们也可能跟Order类是同样的情况
怎么办呢?IOC啊~
那如何IOC啊?使用DI啊~
2、DI(Dependency Injection)——依赖注入
DI是IoC的一种实现方式,就是将依赖对象的创建和绑定转移到被依赖对象类的外面来实现
依赖注入分为:构造函数注入、属性注入和接口注入
(1)构造函数注入
首先,我们为数据访问类SqlServerDal定义一个抽象接口IDataAccess,并在IDataAccess接口中声明GetAll方法:
public interface IDataAccess
{
void Delete();
}
然后在SqlServerDal类中,实现IDataAccess接口:

public class SqlServerDal:IDataAccess
{
public void Delete()
{
Console.WriteLine("删除表中某个订单信息!");
}
}

接下来,我们还需要修改Order类:

public class Order
{
private IDataAccess da; //构造函数注入
public Order(IDataAccess ida)
{
da = ida;
}
public void Delete()
{
da.Delete();
}
}

下面是控制台程序调用的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace IOCDemo
{
class Program
{
static void Main(string[] args)
{
SqlServerDal dal = new SqlServerDal();//在Order类外部创建依赖对象
Order order = new Order(dal);//通过构造函数注入依赖
order.Delete();
Console.Read();
}
}
}

(2)属性注入
属性注入就是通过属性来传递依赖。因此,我们首先需要在依赖类Order中定义一个属性:

public class Order
{
private IDataAccess _da;
//属性,接受依赖
public IDataAccess da
{
set { _da = value; }
get { return _da; }
}
public void Delete()
{
_da.Delete();
}
}

下面是控制台程序调用的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace IOCDemo
{
class Program
{
static void Main(string[] args)
{
AccessDal dal = new AccessDal();//在外部创建依赖对象
Order order = new Order();
order.da = dal;//给属性赋值
order.Delete();
Console.Read();
}
}
}

(3)接口注入
相比构造函数注入和属性注入,用起来没有它们方便。首先定义一个接口,包含一个设置依赖的方法。
public interface IDependent
{
void SetDependence(IDataAccess ida);//设置依赖项
}
用依赖类实现这个接口:

public class Order : IDependent
{
private IDataAccess _ida;
public void SetDependence(IDataAccess ida)
{
_ida = ida;
}
public void Delete()
{
_ida.Delete();
}
}

下面是控制台程序调用的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace IOCDemo
{
class Program
{
static void Main(string[] args)
{
AccessDal dal = new AccessDal();//在Order外部创建依赖对象
Order order = new Order();
order.SetDependence(dal);//传递依赖
order.Delete();
Console.Read();
}
}
}

3、IoC容器
前面所有的栗子中,我们都是通过手动的方式来创建依赖对象,并将引用传递给被依赖模块。比如:
SqlServerDal dal = new SqlServerDal();//在Order外部创建依赖对象
Order order = new Order(dal);//通过构造函数注入依赖
对于大型项目来说,相互依赖的组件比较多。如果还用手动的方式,自己来创建和注入依赖的话,显然效率很低,而且往往还会出现不可控的场面。因此,IoC容器就诞生了。IoC容器实际上是一个DI框架,它能简化我们的工作量。它包含以下几个功能:
- 动态创建、注入依赖对象。
- 管理对象生命周期。
- 映射依赖关系。
本篇我们使用微软框架组给提供的Unity来实现依赖注入,它是最流行的IOC容器之一
二、Unity的使用
1、Unity是个什么东东?
Unit是微软patterns& practices组用C#实现的轻量级、可扩展的依赖注入容器,我们可以通过代码或者XML配置文件的形式来配置对象与对象之间的关系,在运行时直接调用Unity容器即可获取我们所需的对象,以便建立松散耦合的应用程序。
对于小型项目:用代码的方式实现即可
对于中大型项目:使用配置文件比较好
2、Unity入门
您可以访问http://unity.codeplex.com/releases得到最新版本的Unity,也可以直接在Nuget中获取到最新版本的Unity,或者下载微软的企业库,然后在项目中添加Microsoft.Practices.Unity.dll和Microsoft.Practices.Unity.Configuration.dll的引用
这里用到的最重要的东东就是IUnityContainer 接口,它本身定义了很多方法,当然还有一些扩展方法,具体的接口定义这里就不说了,我们会经常用到IUnityContainer 接口的RegisterInstance、RegisterType、Resolve等方法。
这里我举个栗子,首先定义如下接口,并用两个类来进行实现:

/// <summary>
/// 班级接口
/// </summary>
public interface IClass
{
string ClassName { get; set; }
void ShowInfo();
} /// <summary>
/// 计科班
/// </summary>
public class CbClass : IClass
{
public string ClassName { get; set; }
public void ShowInfo()
{
Console.WriteLine("计科班:{0}", ClassName);
}
} /// <summary>
/// 电商班
/// </summary>
public class EcClass : IClass
{
public string ClassName { get; set; }
public void ShowInfo()
{
Console.WriteLine("电商班:{0}", ClassName);
}
}

(1)用编程方式实现注入
使用Unity来管理对象与对象之间的关系可以分为以下几步:
A、创建一个UnityContainer对象
B、通过UnityContainer对象的RegisterType方法来注册对象与对象之间的关系
C、通过UnityContainer对象的Resolve方法来获取指定对象关联的对象
注入代码如下:

public static void ContainerCodeTest()
{
IUnityContainer container = new UnityContainer();
//默认注册(无命名),如果后面还有默认注册会覆盖前面的
container.RegisterType<IClass, CbClass>();
//命名注册
container.RegisterType<IClass, EcClass>("ec");
//解析默认对象
IClass cbClass = container.Resolve<IClass>();
cbClass.ShowInfo();
//指定命名解析对象
IClass ecClass = container.Resolve<IClass>("ec");
ecClass.ShowInfo();
//获取容器中所有IClass的注册的已命名对象
IEnumerable<IClass> classList = container.ResolveAll<IClass>();
foreach (var item in classList)
{
item.ShowInfo();
}
}

(2)配置文件方式
通过配置文件配置Unity信息需要有以下几个步骤:
A、在配置文件<configSections> 配置节下注册名为unity的section
B、在<configuration> 配置节下添加Unity配置信息
C、在代码中读取配置信息,并将配置载入到UnityContainer中
配置文件内容如下:

<?xml version="1.0" encoding="utf-8"?>
<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>
<!--定义类型别名-->
<aliases>
<add alias="IClass" type="ConsoleApplication1.UnityDemo.IClass,ConsoleApplication1" />
<add alias="CbClass" type="ConsoleApplication1.UnityDemo.CbClass,ConsoleApplication1" />
<add alias="EcClass" type="ConsoleApplication1.UnityDemo.EcClass,ConsoleApplication1" />
</aliases>
<!--容器-->
<container name="FirstClass">
<!--映射关系-->
<register type="IClass" mapTo="CbClass"></register>
<register type="IClass" mapTo="EcClass" name="ec"></register>
</container>
</unity>
</configuration>

注入代码如下:

public static void ContainerConfiguration()
{
IUnityContainer container = new UnityContainer();//获取指定名称的配置节
UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
container.LoadConfiguration(section, "FirstClass");//获取特定配置节下已命名的配置节<container name="FirstClass">下的配置信息
IClass classInfo = container.Resolve<IClass>("ec");
classInfo. ShowInfo();
}

注意:
如果系统比较庞大,那么对象之间的依赖关系可能就会很复杂,最终导致配置文件变得很大,所以我们需要将Unity的配置信息从App.config或web.config中分离出来到某一个单独的配置文件中,比如Unity.config,然后将其作为参数传递给下面的方法,依然可以实现依赖注入:

public static void ContainerConfigurationFromFile(string configFile)
{
//根据文件名获取指定config文件
var fileMap = new ExeConfigurationFileMap { ExeConfigFilename = configFile };
//从config文件中读取配置信息
Configuration configuration =
ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
var unitySection = (UnityConfigurationSection)configuration.GetSection("unity");
var container = new UnityContainer().LoadConfiguration(unitySection, "FirstClass");
IClass classInfo = container.Resolve<IClass>("ec");
classInfo.ShowInfo();
}

3、使用Unity为已存在的对象注册关系
在日常开发的过程中我们有时候会自己创建好一个对象,但是你又想对这个已经创建好的对象的生命周期进行管理,这个时候你可以使用Unity提供的RegisterInstance方法(有很多重载),由于RegisterInstance是对已存在的实例进行注册,所以无法通过配置文件来进行配置。
代码示例如下:

public static void RegisterInstance()
{
IClass myClass = new MyClass();
IClass yourClass = new YourClass();
//为myClass实例注册默认实例
container.RegisterInstance<IClass>(myClass);
//为yourClass实例注册命名实例,同RegisterType
container.RegisterInstance<IClass>("yourInstance", yourClass);
container.Resolve<IClass>().ShowInfo();
container.Resolve<IClass>("yourInstance").ShowInfo();
}

这段代码很简单,就是使用RegisterInstance方法将已存在的实例myClass、yourClass等注册到UnityContainer中,默认情况下其实用的是ContainerControlledLifetimeManager,这个生命周期是由UnityContainer来进行管理,UnityContainer会维护一个对象实例的强引用,当你将已存在的实例注册到UnityContainer后,每次通过Resolve方法获取对象都是同一对象,也就是单件实例(singleton instance),具体有关生命周期相关信息在下面进行介绍。
注意是单实例哦~
4、Unity中生命周期管理
我们在系统中引入Unity主要就是想通过Unity来解除对象之间的依赖关系,方便我们根据配置调用到所需的对象,而Unity默认情况下会自动帮我们维护好这些对象的生命周期,可能Unity自动维护的生命周期并不总是我们想要的,这时我们就要根据具体的需求来更改这些对象的生命周期,下面就简单介绍一下Unity中内置的两个常用生命周期管理器,其他的生命周期管理器如果需要可以自己上网查看其详细说明。
(1)TransientLifetimeManager,瞬态生命周期,默认情况下,在使用RegisterType进行对象关系注册时如果没有指定生命周期管理器则默认使用这个生命周期管理器,这个生命周期管理器就如同其名字一样,当使用这种管理器的时候,每次通过Resolve或ResolveAll调用对象的时候都会重新创建一个新的对象。
代码如下:

public static void TransientLifetimeManagerCode()
{
//以下2种注册效果是一样的
container.RegisterType<IClass, MyClass>();
container.RegisterType<IClass, MyClass>(new TransientLifetimeManager());
Console.WriteLine("-------TransientLifetimeManager Begin------");
Console.WriteLine("第一次调用RegisterType注册的对象HashCode:" +
container.Resolve<IClass>().GetHashCode());
Console.WriteLine("第二次调用RegisterType注册的对象HashCode:" +
container.Resolve<IClass>().GetHashCode());
Console.WriteLine("-------TransientLifetimeManager End------");
}

如果是使用配置的方式,则需要在配置文件中注册关系的时候在<register>配置节下新增<lifetime>既可(如果不新增则默认使用TransientLifetimeManager),如果想使用其他的生命周期管理器,则更改此配置节即可!
其中<lifetime>有3个参数:
- type,生命期周期管理器的类型,这边可以选择Unity内置的,也可以使用自定义的,其中内置的生命周期管理器会有智能提示
- typeConverter,生命周期管理器转换类,用户自定义一个生命周期管理器的时候所创建一个转换器
- value,初始化生命周期管理器的值
如果用此生命周期管理器,则要在配置文件中新增的节点如下:
<register type="IClass" mapTo="MyClass">
<lifetime type="transient" />
</register>
注入代码如下:

public static void TransientLifetimeManagerConfiguration()
{
//获取指定名称的配置节
UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
container.LoadConfiguration(section, "FirstClass");
Console.WriteLine("-------TransientLifetimeManager Begin------");
Console.WriteLine("第一次调用RegisterType注册的对象HashCode:" +
container.Resolve<IClass>("transient").GetHashCode());
Console.WriteLine("第二次调用RegisterType注册的对象HashCode:" +
container.Resolve<IClass>("transient").GetHashCode());
Console.WriteLine("-------TransientLifetimeManager End------");
}

以上无论是代码还是配置的方式,运行之后都会发现实例的哈希码是不一样的,说明每次调用都是重新生成一个对象实例!
(2)ContainerControlledLifetimeManager,容器控制生命周期管理,这个生命周期管理器是RegisterInstance默认使用的生命周期管理器,也就是单件实例,UnityContainer会维护一个对象实例的强引用,每次调用的时候都会返回同一对象,示例代码如下:

public static void ContainerControlledLifetimeManagerCode()
{
IClass myClass = new MyClass();
//以下2种注册效果是一样的
container.RegisterInstance<IClass>("ccl", myClass);
container.RegisterInstance<IClass>("ccl", myClass, new ContainerControlledLifetimeManager());
container.RegisterType<IClass, MyClass>(new ContainerControlledLifetimeManager());
Console.WriteLine("-------ContainerControlledLifetimeManager Begin------");
Console.WriteLine("第一次调用RegisterType注册的对象HashCode:" + container.Resolve<IClass>().GetHashCode());
Console.WriteLine("第二次调用RegisterType注册的对象HashCode:" + container.Resolve<IClass>().GetHashCode());
Console.WriteLine("第一次调用RegisterInstance注册的对象HashCode:" + container.Resolve<IClass>("ccl").GetHashCode());
Console.WriteLine("第二次调用RegisterInstance注册的对象HashCode:" + container.Resolve<IClass>("ccl").GetHashCode());
Console.WriteLine("-------ContainerControlledLifetimeManager End------");
}

运行之后都会发现实例的哈希码是一样的,说明是单实例的
如果用此生命周期管理器,则要在配置文件中新增的节点如下:
<register type="IClass" mapTo="MyClass" name="ccl">
<lifetime type="singleton" />
</register>
注入代码与上例类似,这里不再列出
三、ASP.NET MVC与Unity
说了这么多Unity,主要还是想将其用到ASP.NET MVC的IOC中,其实很简单,大概就几个步骤搞定:
1. 实现IDependencyResolver接口并通过DependencyResolver.SetResolver告知MVC,将部分类型实例解析工作交由IoC容器Unity来处理

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Microsoft.Practices.Unity; namespace UnityOfMVC.IOC
{
public class UnityDependencyResolver : IDependencyResolver
{
IUnityContainer container; public UnityDependencyResolver(IUnityContainer container)
{
this.container = container;
} public object GetService(Type serviceType)
{
if (!this.container.IsRegistered(serviceType))
{
return null;
}
return container.Resolve(serviceType);
} public IEnumerable<object> GetServices(Type serviceType)
{
return container.ResolveAll(serviceType);
} }
}

2、继承DefaultControllerFactory,重载GetControllerInstance方法,实现自己的UnityControllerFactory类,并通过IoC容器将之注册为IControllerFactory的实现

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Microsoft.Practices.Unity;
using System.Web.SessionState; namespace UnityOfMVC.IOC
{
public class UnityControllerFactory : DefaultControllerFactory
{
IUnityContainer container;
public UnityControllerFactory(IUnityContainer container)
{
this.container = container;
} protected override IController GetControllerInstance(RequestContext reqContext, Type controllerType)
{
return container.Resolve(controllerType) as IController;
}
}
}

3、让我们开始弄一下配置文件

<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
Microsoft.Practices.Unity.Configuration" />
</configSections>
<unity>
<containers>
<container name="defaultContainer">
<register type="UnityOfMVC.Models.IStudentRepository, UnityOfMVC" mapTo="UnityOfMVC.Models.StudentRepository, UnityOfMVC"/>
<register type="System.Web.Mvc.IControllerFactory, System.Web.Mvc" mapTo="UnityOfMVC.IOC.UnityControllerFactory, UnityOfMVC"/>
</container>
</containers>
</unity>

4、用引导类Bootstrapper进行初始化工作

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Configuration;
using System.Web.Mvc;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using UnityOfMVC.IOC; namespace UnityOfMVC.BootStrapper
{
public class Bootstrapper
{
public static IUnityContainer Init()
{
var container = BuildUnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
return container;
} private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer(); UnityConfigurationSection configuration = (UnityConfigurationSection)ConfigurationManager.GetSection(UnityConfigurationSection.SectionName);
configuration.Configure(container, "defaultContainer"); return container;
} }
}

5、在函数Application_Start() 中进行真正的初始化工作

public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AuthConfig.RegisterAuth();
BootStrapper.Bootstrapper.Init(); //就是这个东东
}
}

6、现在在你的MVC程序中注入依赖代码就ok了
(1)首先声明一个Student学生类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web; namespace UnityOfMVC.Models
{
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public string Graduation { get; set; }
public string School { get; set; }
public string Major { get; set; }
}
}

(2)然后声明仓储接口和其实现

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace UnityOfMVC.Models
{
public interface IStudentRepository
{
IEnumerable<Student> GetAll();
Student Get(int id);
Student Add(Student item);
bool Update(Student item);
bool Delete(int id);
}
}

(3)最后添加控制器StudentController,并注入依赖代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using UnityOfMVC.Models; namespace UnityOfMVC.Controllers
{
public class StudentController : Controller
{
readonly IStudentRepository repository;
//构造器注入
public StudentController(IStudentRepository repository)
{
this.repository = repository;
} public ActionResult Index()
{
var data = repository.GetAll();
return View(data);
} }
}

(4)最后为控制器StudentController的Index方法添加视图即可,这里不再详述,运行效果如下:
ASP.NET MVC IOC之Unity攻略的更多相关文章
- ASP.NET MVC IOC 之Ninject攻略
ASP.NET MVC IOC 之Ninject攻略 一.为什么要使用Ninject? 很多其它类型的IOC容器过于依赖配置文件,老是配置,总感觉有点不爽,而且要使用assembly-qualifie ...
- [转]ASP.NET MVC IOC 之AutoFac攻略
本文转自:http://www.cnblogs.com/WeiGe/p/3871451.html 一.为什么使用AutoFac? 之前介绍了Unity和Ninject两个IOC容器,但是发现园子里用A ...
- ASP.NET MVC IOC 之AutoFac攻略
一.为什么使用AutoFac? 之前介绍了Unity和Ninject两个IOC容器,但是发现园子里用AutoFac的貌似更为普遍,于是捯饬了两天,发现这个东东确实是个高大上的IOC容器~ Autofa ...
- ASP.NET MVC Razor视图引擎攻略
--引子 看下面一段MVC 2.0的代码. <%if (Model != null){%> <p><%=Model%></p><%}%>&l ...
- ASP.NET MVC IOC 之AutoFac
ASP.NET MVC IOC 之AutoFac攻略 一.为什么使用AutoFac? 之前介绍了Unity和Ninject两个IOC容器,但是发现园子里用AutoFac的貌似更为普遍,于是捯饬了两天, ...
- ASP.NET MVC中使用Unity进行依赖注入的三种方式
在ASP.NET MVC中使用Unity进行依赖注入的三种方式 2013-12-15 21:07 by 小白哥哥, 146 阅读, 0 评论, 收藏, 编辑 在ASP.NET MVC4中,为了在解开C ...
- ASP.NET没有魔法——ASP.NET MVC IoC
之前的文章介绍了MVC如何通过ControllerFactory及ControllerActivator创建Controller,而Controller又是如何通过ControllerBase这个模板 ...
- ASP.NET MVC IOC依赖注入之Autofac系列(二)- WebForm当中应用
上一章主要介绍了Autofac在MVC当中的具体应用,本章将继续简单的介绍下Autofac在普通的WebForm当中的使用. PS:目前本人还不知道WebForm页面的构造函数要如何注入,以下在Web ...
- ASP.NET没有魔法——ASP.NET MVC IoC代码篇
上一篇文章主要以文字的形式介绍了IoC及其在ASP.NET MVC中的使用,本章将从以下几点介绍如何使用代码在ASP.NET MVC中实现依赖注入: ● AutoFac及安装 ● 容器的创建 ● 创建 ...
随机推荐
- apk当安装程序将文件复制到手机自带的指定文件夹
项目已获得,今天.apk文件以获得另一个非调试手机,发现一个问题. 由于涂料.所以绘图数据的点存储在一个.txt文字档.把它用usb传到指定目录下的,可是明显不科学,由于用户下载了你的.apk文件,你 ...
- UI測试内容
我们在实际工作其中,针对web应用程序,也就是常常所说的B/S系统,能够从例如以下方面来进行用户界面測试: 导航測试 导航描写叙述了用户在一个页面内操作的方式,在不同的用户接口控制之间,比如butto ...
- ABP日志管理
ABP日志管理 基于DDD的现代ASP.NET开发框架--ABP系列之8.ABP日志管理 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ABP ...
- DropDownListFor使用ViewData进行绑定的示例
特别注意,经实践: 此方法的ViewBag的名称必须和new SelectList()中的最后一个参数,即下拉框的默认值的名称必须相同,如: ViewBag.Title = WebConst.UnSe ...
- do...while(0)神奇
1. do...while(0)消除goto语句. 通常,假设在一个函数中開始要分配一些资源.然后在中途运行过程中假设遇到错误则退出函数,当然,退出前先释放资源,我们的代码可能是这样: version ...
- js中prototype用法(转)
JavaScript能够实现的面向对象的特征有:·公有属性(public field)·公有方法(public Method)·私有属性(private field)·私有方法(private fie ...
- HTML5 画一张图
笔者:本笃庆军 原文地址:http://blog.csdn.net/qingdujun/article/details/33344289 一.绘制图像 使用drawImage()方法绘制图像. 画图环 ...
- C++调用一个成员函数的需求this指针的情况
1.虚成员函数,因为需要this展望虚表指针的指针 2.在数据成员的操作部件的功能 #include "stdafx.h" #include <iostream> #i ...
- jQuery UI的datepicker日期控件如何让他显示中文
首先是引入UI的JS文件和模板文件,如下: <link rel=”stylesheet” href=”./ui/themes/le-frog/jquery.ui.all.css”> < ...
- ListView排序并隔色显示
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.C ...