1、前言
在实际开发业务中,泛型的应用非常广泛,而这也就产生了一个问题:泛型类和泛型接口该怎么注册?难道要开发者一行一行去写泛型构造参数吗?同时,实际业务中往往也会对项目进行分层设计,例如接口层、实现层。对于这种处于不同程序集的接口和类,又有没有什么高效的方法对其进行处理呢?本文就来介绍一下如何利用Autofac
来处理这两类问题。
2、Autofac中的泛型注册
新建泛型接口、泛型类、实体类,代码如下:
public interface IService<TEntity> where TEntity : class
{
string Get();
}
public class Service<TEntity> : IService<TEntity> where TEntity : class
{
public string Get()
{
return typeof(TEntity).FullName;
}
}
public class Cat { }
public class Dog { }
如果使用Autofac
中的基础注册方法,代码如下:
using Autofac;
using System;
namespace App
{
internal class Program
{
static void Main(string[] args)
{
// 注册接口和类
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<Service<Cat>>().As<IService<Cat>>();
builder.RegisterType<Service<Dog>>().As<IService<Dog>>();
// 构建容器
IContainer container = builder.Build();
// Cat
IService<Cat> cat = container.Resolve<IService<Cat>>();
Console.WriteLine(cat.Get());
// Dog
IService<Dog> dog = container.Resolve<IService<Dog>>();
Console.WriteLine(dog.Get());
}
}
}
运行结果如下所示:
App.Cat
App.Dog
上面的代码虽然实现了泛型注册,但问题也是显而易见的:一旦实体类数量较多,开发者需要手写大量注册代码。在Autofac
中,我们可以使用RegisterGeneric
方法来实现泛型注册,代码如下:
using Autofac;
using System;
namespace App
{
internal class Program
{
static void Main(string[] args)
{
// 注册接口和类
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterGeneric(typeof(Service<>)).As(typeof(IService<>));
// 构建容器
IContainer container = builder.Build();
// Cat
IService<Cat> cat = container.Resolve<IService<Cat>>();
Console.WriteLine(cat.Get());
// Dog
IService<Dog> dog = container.Resolve<IService<Dog>>();
Console.WriteLine(dog.Get());
}
}
}
使用RegisterGeneric
方法的好处就是无需写大量的带泛型构造参数的注册代码。运行结果如下所示:
App.Cat
App.Dog
3、Autofac中的程序集注册
在实际业务中,一般会对项目进行分层设计。下图显示了一个简易的分层项目:
Repository
层代码如下所示:
namespace App.Repository.Contract
{
public interface ICatRepository
{
string GetCatMsg();
}
}
namespace App.Repository.Contract
{
public interface IDogRepository
{
string GetDogMsg();
}
}
using App.Repository.Contract;
namespace App.Repository
{
public class CatRepository : ICatRepository
{
public string GetCatMsg()
{
return "This is cat";
}
}
}
using App.Repository.Contract;
namespace App.Repository
{
public class DogRepository : IDogRepository
{
public string GetDogMsg()
{
return "This is dog";
}
}
}
Service
层代码如下所示:
namespace App.Service.Contract
{
public interface ICatService
{
string Get();
}
}
namespace App.Service.Contract
{
public interface IDogService
{
string Get();
}
}
using App.Repository.Contract;
using App.Service.Contract;
namespace App.Service
{
public class CatService : ICatService
{
protected readonly ICatRepository _repository;
public CatService(ICatRepository repository)
{
_repository = repository;
}
public string Get()
{
return _repository.GetCatMsg();
}
}
}
using App.Repository.Contract;
using App.Service.Contract;
namespace App.Service
{
public class DogService : IDogService
{
protected readonly IDogRepository _repository;
public DogService(IDogRepository repository)
{
_repository = repository;
}
public string Get()
{
return _repository.GetDogMsg();
}
}
}
如果使用Autofac
的基础注册方法,可以写成如下形式:
using App.Repository;
using App.Repository.Contract;
using App.Service;
using App.Service.Contract;
using Autofac;
using System;
namespace App
{
internal class Program
{
static void Main(string[] args)
{
// 注册接口和类
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<CatRepository>().As<ICatRepository>();
builder.RegisterType<DogRepository>().As<IDogRepository>();
builder.RegisterType<CatService>().As<ICatService>();
builder.RegisterType<DogService>().As<IDogService>();
// 构建容器
IContainer container = builder.Build();
// ICatService
ICatService cat = container.Resolve<ICatService>();
Console.WriteLine(cat.Get());
// IDogService
IDogService dog = container.Resolve<IDogService>();
Console.WriteLine(dog.Get());
}
}
}
运行结果如下所示:
This is cat
This is dog
上面的代码虽然能够实现注册,但其实问题跟泛型注册一样:如果有很多接口和类,那么就需要写大量重复代码。一般来说,分层项目会对各层中的文件命名做一定的限制。例如,仓储层中的文件必须以Repository
结尾,服务层中的文件必须以Service
结尾。这就给我们提供了一个思路:能否通过加载程序集批量获取文件名称,通过文件名称的匹配来实现接口和类的注册?其实,Autofac
中的RegisterAssemblyTypes
方法就支持这么做,代码如下:
using App.Service.Contract;
using Autofac;
using System;
using System.Reflection;
namespace App
{
internal class Program
{
static void Main(string[] args)
{
// 注册接口和类
ContainerBuilder builder = new ContainerBuilder();
// 注册Repository
Assembly repository = Assembly.Load("App.Repository");
Assembly repositoryContract = Assembly.Load("App.Repository.Contract");
builder.RegisterAssemblyTypes(repository, repositoryContract)
.Where(p => p.Name.EndsWith("Repository"))
.AsImplementedInterfaces();
// 注册Service
Assembly service = Assembly.Load("App.Service");
Assembly serviceContract = Assembly.Load("App.Service.Contract");
builder.RegisterAssemblyTypes(service, serviceContract)
.Where(p => p.Name.EndsWith("Service"))
.AsImplementedInterfaces();
// 构建容器
IContainer container = builder.Build();
// ICatService
ICatService cat = container.Resolve<ICatService>();
Console.WriteLine(cat.Get());
// IDogService
IDogService dog = container.Resolve<IDogService>();
Console.WriteLine(dog.Get());
}
}
}
运行结果如下所示:
This is cat
This is dog
程序集注册的好处是显而易见的:如果后续需要添加新的接口和类,我们也不需要修改代码,因为Autofac
会自动扫描类库中文件,然后通过名称匹配进行注册。
4、结语
本文主要介绍了Autofac
中的泛型注册和程序集注册,这两种注册方法具有非常高的实用性。如果你对项目进行了分层设计,同时项目中也存在大量泛型接口和泛型类,那么使用泛型注册和程序集注册将会达到事半功倍的效果。