效果

原类(必须是MarshalByRefObject的派生类)

1
2
3
4
5
public class Person : MarshalByRefObject {
public string Say(string word) {
return $"Hello,{word}!";
}
}

切片类

1
2
3
4
5
6
7
8
9
public class PersonAspect {
[Around(typeof(string))]
public void Say(JoinPoint joinPoint) {
var args = joinPoint.args;
Console.WriteLine("调用之前:收到了" + args[0]);
var result = joinPoint.Procced();
Console.WriteLine("调用之后:结果是" + result);
}
}

使用

1
2
3
4
5
static void Main(string[] args) {
Person p = (Person) new AopRealProxy(typeof(Person), null, typeof(PersonAspect), null).GetTransparentProxy();
p.Say("World");
Console.Read();
}

输出结果

调用之前:收到了World
调用之后:结果是Hello,World!

实现

定义JoinPoint(切点类)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
using System;
using System.Runtime.Remoting.Messaging;

namespace KanameFramework.Core.Aop {

/// <summary>
/// 切点
/// </summary>
public class JoinPoint {

public object[] args;
private Func<IMethodReturnMessage> procced;

public IMethodReturnMessage MethodReturnMessage { get; private set; }

public JoinPoint(object[] args, Func<IMethodReturnMessage> procced) {
this.args = args;
this.procced = procced;
}

/// <summary>
/// 执行原方法
/// </summary>
public object Procced() {
MethodReturnMessage = procced.Invoke();
return MethodReturnMessage.ReturnValue;
}

}

}

定义注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System;

namespace KanameFramework.Core.Aop.Attributes {
/// <summary>
/// 标记此方法为环绕通知
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class AroundAttribute: Attribute {

/// <summary>
/// 方法的参数列表,用于寻找(重载的)方法
/// </summary>
public Type[] ArgTypes { get; private set; }

public AroundAttribute() {
ArgTypes = new Type[0];
}

public AroundAttribute(params Type[] argTypes) {
ArgTypes = argTypes;
}
}
}

继承RealProxy,并实现基本功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
using KanameFramework.Core.Aop.Attributes;
using System;
using System.Linq;
using System.Reflection;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;
using System.Security.Permissions;

namespace KanameFramework.Core.Aop {

/// <summary>
/// 提供动态代理的基本功能
/// </summary>
public class AopRealProxy : RealProxy {

private string URI;
private Type aspectType;
private object aspectInstance;

/// <summary>
/// 组合目标类和切面类
/// </summary>
/// <param name="type">目标类</param>
/// <param name="typeIns">目标类实例</param>
/// <param name="aspectType">切面类</param>
/// <param name="aspectIns">切面类实例</param>
[PermissionSet(SecurityAction.LinkDemand)]
public AopRealProxy(Type type,object typeIns,Type aspectType, object aspectIns) : base(type) {
this.aspectType = aspectType;
this.aspectInstance = aspectIns??Activator.CreateInstance(aspectType);
URI = RemotingServices.Marshal((MarshalByRefObject)(typeIns??Activator.CreateInstance(type))).URI;
}

[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
public override IMessage Invoke(IMessage message) {

//获取参数值
var properties = message.Properties;
var methodName = (string)properties["__MethodName"];
var argTypes = (Type[])properties["__MethodSignature"];
var args = (object[])properties["__Args"];

//切面类匹配到的的方法
var matchAspectMethods = aspectType.GetMethods(BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance).Where(m=> {
if (!m.Name.Equals(methodName)) return false;
var attr = m.GetCustomAttribute<AroundAttribute>();
if (attr == null) return false;
return attr.ArgTypes.SequenceEqual(argTypes);
});

//确定执行前设置uri
properties["__Uri"] = URI;

//切面类没有对应方法直接返回
if (matchAspectMethods.Count()<1)
return (IMethodReturnMessage)ChannelServices.SyncDispatchMessage(message);

//交给切面类执行
var joinPoint = new JoinPoint(args, () => (IMethodReturnMessage)ChannelServices.SyncDispatchMessage(message));
matchAspectMethods.First().Invoke(aspectInstance, new object[] { joinPoint });
return joinPoint.MethodReturnMessage;
}
}
}