Introduction
In this example, we will use the logic as simple as possible to implement all functional requirements, which will highlight the core issues we want to solve. The example is a simple calculator class:
Public class Calculator
{
Public int add (int x, int y) {return X + Y ;}
}
This class is no longer simple, but if you think of it as a more complex business processing class, you will face more details than the core function implementation, such: permission control, audit logs, performance monitoring, buffer processing, transaction environment, and so on. For simplicity, we first add the logging function for this class. This function requires that the call and processing results of each method be output to the console, as shown below:
Public class Calculator
{
Public int add (int x, int y)
{
Console. Write ("add ({0}, {1})", x, y );
Int result = x + y;
Console. writeline ("= {0}", result );
Return result;
}
}
That's easy, right? Now we need to monitor the performance of this method as follows:
Public class Calculator
{
Public int add (int x, int y)
{
Console. Write ("add ({0}, {1})", x, y );
Datetime timebegin = system. datetime. now;
Int result = x + y;
Timespan timeinter = system. datetime. Now-timebegin;
Console. Write ("[{0}]", timeinter );
Console. writeline ("= {0}", result );
Return result;
}
}
At this point, you already feel that although we have implemented the required functions, we have stacked the differences in a method to handle various matters.Code. Although this simple example won't feel uncomfortable, you can imagine what will happen if we will add a second method for this class:
Public class Calculator
{
Public int add (int x, int y)
{
Console. Write ("add ({0}, {1})", x, y );
Datetime timebegin = system. datetime. now;
Int result = x + y;
Timespan timeinter = system. datetime. Now-timebegin;
Console. Write ("[{0}]", timeinter );
Console. writeline ("= {0}", result );
Return result;
}
Public int subtract (int x, int y)
{
Console. Write ("Subtract ({0}, {1})", x, y );
Datetime timebegin = system. datetime. now;
Int result = x-y;
Timespan timeinter = system. datetime. Now-timebegin;
Console. Write ("[{0}]", timeinter );
Console. writeline ("= {0}", result );
Return result;
}
}
The Code already exists in the two methods, which is not a good solution-think about it if there are 10 methods in our calculator? What if we have dozens of other classes similar to the calculator class? What if we still have more method-level functions to implement (permission control, transaction management ......)? This is a common problem in enterprise-level application development. For clarity, we break down the problem into two parts. The primary issue is obfuscation of code responsibilities, second, the same code logic is repeated multiple times-these problems will lead to various difficulties in development management, code writing and maintenance.
Solution 1: manually write a proxy
1. First, we define the interface icalculator:
Using system;
Namespace proxy
{
Public interface icalculator
{
Int add (int x, int y );
Int subtract (int x, int y );
}
}
2. Implement an interface:
Using system;
Namespace proxy
{
Public class calculator: icalculator
{
Public Virtual int add (int x, int y)
{
Int result = x + y;
Return result;
}
Public Virtual int subtract (int x, int y)
{
Int result = x-y;
Return result;
}
}
}
3. Compile a proxy class that adds log and Performance Detection Functions
The logging function is added, that is, the function requires that the call and processing results of each method be output to the console, and performance monitoring is added.
There are two implementation methods, one of which is commented out
Using system;
Namespace proxy
{
///// <Summary>
///// Summary of calproxy.
///// </Summary>
// Public class calproxy: icalculator
//{
// Private calculator _ calculator;
// Public calproxy ()
//{
// This. _ calculator = new calculator ();
//}
// Private datetime timebegin = system. datetime. now;
// Private void predosomething (int x, int y)
//{
// Timebegin = system. datetime. now;
// Console. Write ("number ({0}, {1}) \ n", x, y );
//}
//// Implement add
// Public Virtual int add (int x, int y)
//{
// This. predosomething (x, y );
// Int result = This. _ calculator. Add (x, y );
// This. postdosomething (result );
// Return result;
//}
//// Implement sub
// Public Virtual int subtract (int x, int y)
//{
// This. predosomething (x, y );
// Int result = This. _ calculator. Subtract (x, y );
// This. postdosomething (result );
// Return result;
//}
// Private void postdosomething (INT result)
//{
// Timespan timeinter = system. datetime. Now-timebegin;
// Console. Write ("RunTime [{0}] \ n", timeinter );
// Console. writeline ("running result = {0} \ n", result );
//}
//}
/// <Summary>
/// Summary of calproxy.
/// </Summary>
Public class calproxy: Calculator
{
Public calproxy ()
{}
Private datetime timebegin = system. datetime. now;
Private void predosomething (int x, int y)
{
Timebegin = system. datetime. now;
Console. Write ("number ({0}, {1}) \ n", x, y );
}
// Implement add
Public override int add (int x, int y)
{
This. predosomething (x, y );
Int result = base. Add (x, y );
This. postdosomething (result );
Return result;
}
// Implement sub
Public override int subtract (int x, int y)
{
This. predosomething (x, y );
Int result = base. Subtract (x, y );
This. postdosomething (result );
Return result;
}
Private void postdosomething (INT result)
{
Timespan timeinter = system. datetime. Now-timebegin;
Console. Write ("running time [{0}] \ n", timeinter );
Console. writeline ("running result = {0} \ n", result );
}
}
}
4. External call Methods
Icalculator ical = new proxy. calproxy ();
Ical. Add (5, 3 );
Ical. Subtract (7,2 );
RunProgramResult:
Number (5, 3)
Run Time [00:00:02. 0156250]
Running result = 8
Number (7,2)
Running time [00:00:03]
Running result = 5
Solution 2: Implement iinterceptor by using Castle. dynamicproxy
Step 1 and solve the problem
3. Implement standardinterceptor and add log and performance monitoring functions
Standardinterceptor is an implementation class of the iinterceptor interface. We implement standardinterceptor
Using system;
Using system. collections;
Using Castle. dynamicproxy;
Namespace proxy
{
/// <Summary>
/// The proxyinterceptor interceptor implements log and performance monitoring.
/// </Summary>
Public class proxyinterceptor: standardinterceptor
{
Private system. datetime timebegin = system. datetime. now;
Public proxyinterceptor ()
{}
Protected override void postproceed (iinvocation invocation, ref object returnvalue, Params object [] arguments)
{
Timespan timeinter = system. datetime. Now-timebegin;
Console. Write ("running time [{0}] \ n", timeinter );
Console. writeline ("running result = {0} \ n", returnvalue );
Base. postproceed (invocation, ref returnvalue, arguments );
}
Protected override void preproceed (iinvocation invocation, Params object [] ARGs)
{
Console. Write ("number ({0}, {1}) \ n", argS [0], argS [1]);
Timebegin = system. datetime. now;
Base. preproceed (invocation, argS );
}
Public override object intercept (iinvocation invocation, Params object [] ARGs)
{
Preproceed (invocation, argS );
Object retvalue = invocation. Proceed (ARGs );
Postproceed (invocation, ref retvalue, argS );
Return retvalue;
}
}
}
4. Use Castle. dynamicproxy to call
Proxygenerator generator = new proxygenerator ();
Object proxy = generator. createclassproxy (typeof (calculator), new proxyinterceptor ());
Icalculator icalcastle = proxy as icalculator;
Icalcastle. Add (5, 3 );
Icalcastle. Subtract (7,2 );
Implementation process: first, a proxy class is generated by code, which inherits the self-woven class. Then, override the method to be intercepted in the proxy class, encapsulate the invocation object in the covered method, and pass the intercept method of the intercepter object passed in to the user. The intercept method calls the preprocess of intercepter in sequence, and calls the callback function directed to by the delegate passed in through invocation. The postprocess method of intercepter is used to intercepter.
Meaning
In the AOP field, additional functions such as logs, transactions, and caches can be used.