【C#高级语法特性锦集】
C# Unity依赖注入利用Attribute实现AOP功能
在做项目时,常常要对某个功能进行扩展,我们一般都是利用OOP的思想, 在原有的功能上进行扩展。
如果能用AOP思想去扩展,会使代码的整体框架更加稳定,我推荐Unity框架,接下来介绍一下如何使用。
1. 首先通过NuGet添加相关依赖
需要Unity和Unity.Interception
!!重要!!注意!!版本不要选太新版,Unity选5.6.0以前的,Interception也选5.2.0左右的即可,新版使用该案例会出现一些问题,如有解决方法请在评论指出
2. 添加namespace
using Unity;
using Unity.Interception.ContainerIntegration;
using Unity.Interception.Interceptors.InstanceInterceptors.InterfaceInterception;
using Unity.Interception.PolicyInjection.Pipeline;
using Unity.Interception.PolicyInjection.Policies;
3. 开始使用EntLib\PIAB Unity 实现动态代理
3.1 先写好相关特性Attribute,必须继承自HandlerAttribute
#region 特性
public class UserHandlerAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler(IUnityContainer container)
{
ICallHandler handler = new UserHandler() { Order = this.Order };
return handler;
}
}
public class LogHandlerAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler(IUnityContainer container)
{
return new LogHandler() { Order = this.Order };
}
}
public class ExceptionHandlerAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler(IUnityContainer container)
{
return new ExceptionHandler() { Order = this.Order };
}
}
public class AfterLogHandlerAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler(IUnityContainer container)
{
return new AfterLogHandler() { Order = this.Order };
}
}
#endregion 特性
3.2 再写特性对应的行为
注[1]Order:是特性运行的顺序,具体看后面的操作实例
注[2]getNext:运行下一个函数先,如果getNext在前面,那么就是主程序运行完再运行这个特性行为(需要注意Order顺序会反过来),否则就是在特性前(Order顺序正常排序)
注[3]input:输入的参数,input[0]是第一个参数…以此类推
#region 特性对应的行为
public class UserHandler : ICallHandler
{
public int Order { get; set; }
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
User user = input.Inputs[0] as User;
if (user.Password.Length < 10)
{
return input.CreateExceptionMethodReturn(new Exception("密码长度不能小于10位"));
}
Console.WriteLine("参数检测无误");
IMethodReturn methodReturn = getNext()(input, getNext); //getNext.Invoke().Invoke(input, getNext);
//Console.WriteLine("已完成操作");
return methodReturn;
}
}
public class LogHandler : ICallHandler
{
public int Order { get; set; }
/// <summary>
///
/// </summary>
/// <param name="input">方法调用的参数列表</param>
/// <param name="getNext"></param>
/// <returns></returns>
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
User user = input.Inputs[0] as User;
string message = $"RegUser:Username:{user.Name},Password:{user.Password}";
Console.WriteLine("日志已记录,Message:{0},Ctime:{1}", message, DateTime.Now);
return getNext()(input, getNext);
}
}
public class ExceptionHandler : ICallHandler
{
public int Order { get; set; }
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
IMethodReturn methodReturn = getNext()(input, getNext);
if (methodReturn.Exception == null)
{
Console.WriteLine("无异常");
}
else
{
Console.WriteLine($"异常:{methodReturn.Exception.Message}");
}
return methodReturn;
}
}
public class AfterLogHandler : ICallHandler
{
public int Order { get; set; }
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
IMethodReturn methodReturn = getNext()(input, getNext);
User user = input.Inputs[0] as User;
string message = string.Format("RegUser:Username:{0},Password:{1}", user.Name, user.Password);
Console.WriteLine("完成日志,Message:{0},Ctime:{1},计算结果{2}", message, DateTime.Now, methodReturn.ReturnValue);
return methodReturn;
}
}
#endregion 特性对应的行为
3.3 最后写相关的业务(函数方法/功能)
注[1]Order:这里特性的运行顺序是按照Order从小到大排的
注[2]DIP原则:这里最好使用依赖倒置原则来写,操作抽象会使代码更加稳定
#region 业务
[UserHandlerAttribute(Order = 1)]
[LogHandlerAttribute(Order = 2)]
[ExceptionHandlerAttribute(Order = 3)]
[AfterLogHandlerAttribute(Order = 4)]
public interface IUserProcessor
{
void RegUser(User user);
User GetUser(User user);
}
public class UserProcessor : IUserProcessor
{
public void RegUser(User user)
{
Console.WriteLine("用户已注册。");
//throw new Exception("11");
}
public User GetUser(User user)
{
return user;
}
}
#endregion 业务
4. 具体操作实现
注[1]断点:在下面注释需要打断点的那里打断点查看具体运行顺序,以便理解
public static void Show()
{
User user = new User()
{
Name = "Eleven",
Password = "12345678957576"
};
{
UserProcessor processor = new UserProcessor();
processor.RegUser(user);
Console.WriteLine("*********************");
}
{
IUnityContainer container = new UnityContainer();//声明一个容器
container.RegisterType<IUserProcessor, UserProcessor>();//声明UnityContainer并注册IUserProcessor
IUserProcessor processor = container.Resolve<IUserProcessor>();
processor.RegUser(user);//没有AOP的,可在此打个断点F11进入
//配置AOP,固定套路
container.AddNewExtension<Interception>()
.Configure<Interception>()
.SetInterceptorFor<IUserProcessor>(new InterfaceInterceptor());
IUserProcessor userprocessor = container.Resolve<IUserProcessor>();//重新实例化
Console.WriteLine("********************");
userprocessor.RegUser(user);//有AOP的,可在此打个断点F11进入
userprocessor.GetUser(user);//有AOP的,可在此打个断点F11进入
}
}
5. 小结
在这里的Unity实现,主要是用Unity内部的特性去实现AOP,本文介绍的实现方法是静态的,如果需要动态的还需写配置文件。过几天再写一篇Unity实现IOC及AOP的动态配置。