同事搓蛋问了我一个问题,mock的原理是啥,没怎么想出来,于是花了点时间学习了一下。
从Moq这个库入手:https://github.com/moq/moq4
Moq用到了Castle的库用于DynamicProxy的生成和interception,Castle还有IOC的功能,因为每次生成DynamicProxy比较耗时,所以利用IOC还可以做管理和缓存。
Interceptor是一种AOP(Aspect Oriented Programming)思想的实现,Castle里面就是利用了IInterceptor的接口
namespace Castle.DynamicProxy { /// <summary> /// New interface that is going to be used by DynamicProxy 2 /// </summary> public interface IInterceptor { void Intercept(IInvocation invocation); } }
public class MyIntercept : IInterceptor { public void Intercept(IInvocation invocation) { Console.WriteLine(">> intercepted in <<"); invocation.Proceed(); Console.WriteLine(">> intercepted out <<"); } }
你去Mock<T>一个对象实际上就是用到了public partial class Mock<T> : Mock, IMock<T> where T : class的构造函数,当你访问Object对象的时候,实际上调用了GetObject方法去初始化
public object Object { get { return this.GetObject(); } } private object GetObject() { var value = this.OnGetObject();//这是个抽象方法 this.isInitialized = true; return value; }
然后调用子类的OnGetObject()模板方法
protected override object OnGetObject() { if (this.instance == null) { this.InitializeInstance(); } return this.instance; }
private void InitializeInstance() { PexProtector.Invoke(() => { if (this.IsDelegateMock) { // We're mocking a delegate. // Firstly, get/create an interface with a method whose signature // matches that of the delegate. var delegateInterfaceType = proxyFactory.GetDelegateProxyInterface(typeof(T), out delegateInterfaceMethod); // Then create a proxy for that. var delegateProxy = proxyFactory.CreateProxy( delegateInterfaceType, this.Interceptor, this.ImplementedInterfaces.ToArray(), this.constructorArguments); // Then our instance is a delegate of the desired type, pointing at the // appropriate method on that proxied interface instance. this.instance = (T)(object)Delegate.CreateDelegate(typeof(T), delegateProxy, delegateInterfaceMethod); } else { this.instance = (T)proxyFactory.CreateProxy( typeof(T), this.Interceptor, this.ImplementedInterfaces.ToArray(), this.constructorArguments); } }); }
proxyFactory是什么呢?
internal class CastleProxyFactory : IProxyFactory { private static readonly ProxyGenerator generator = CreateProxyGenerator(); [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline", Justification = "By Design")] static CastleProxyFactory() { #pragma warning disable 618 AttributesToAvoidReplicating.Add<SecurityPermissionAttribute>(); #pragma warning restore 618 #if !SILVERLIGHT AttributesToAvoidReplicating.Add<ReflectionPermissionAttribute>(); AttributesToAvoidReplicating.Add<PermissionSetAttribute>(); AttributesToAvoidReplicating.Add<System.Runtime.InteropServices.MarshalAsAttribute>(); AttributesToAvoidReplicating.Add<UIPermissionAttribute>(); #if !NET3x AttributesToAvoidReplicating.Add<System.Runtime.InteropServices.TypeIdentifierAttribute>(); #endif #endif proxyOptions = new ProxyGenerationOptions { Hook = new ProxyMethodHook(), BaseTypeForInterfaceProxy = typeof(InterfaceProxy) }; } /// <inheritdoc /> public object CreateProxy(Type mockType, ICallInterceptor interceptor, Type[] interfaces, object[] arguments) { if (mockType.IsInterface) { return generator.CreateInterfaceProxyWithoutTarget(mockType, interfaces, proxyOptions, new Interceptor(interceptor)); } try { return generator.CreateClassProxy(mockType, interfaces, proxyOptions, arguments, new Interceptor(interceptor)); } catch (TypeLoadException e) { throw new ArgumentException(Resources.InvalidMockClass, e); } catch (MissingMethodException e) { throw new ArgumentException(Resources.ConstructorNotFound, e); } } private static readonly Dictionary<Type, Type> delegateInterfaceCache = new Dictionary<Type, Type>(); private static readonly ProxyGenerationOptions proxyOptions; private static int delegateInterfaceSuffix; /// <inheritdoc /> public Type GetDelegateProxyInterface(Type delegateType, out MethodInfo delegateInterfaceMethod) { Type delegateInterfaceType; lock (this) { if (!delegateInterfaceCache.TryGetValue(delegateType, out delegateInterfaceType)) { var interfaceName = String.Format(CultureInfo.InvariantCulture, "DelegateInterface_{0}_{1}", delegateType.Name, delegateInterfaceSuffix++); var moduleBuilder = generator.ProxyBuilder.ModuleScope.ObtainDynamicModule(true); var newTypeBuilder = moduleBuilder.DefineType(interfaceName, TypeAttributes.Public | TypeAttributes.Interface | TypeAttributes.Abstract); var invokeMethodOnDelegate = delegateType.GetMethod("Invoke"); var delegateParameterTypes = invokeMethodOnDelegate.GetParameters().Select(p => p.ParameterType).ToArray(); // Create a method on the interface with the same signature as the delegate. newTypeBuilder.DefineMethod("Invoke", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Abstract, CallingConventions.HasThis, invokeMethodOnDelegate.ReturnType, delegateParameterTypes); delegateInterfaceType = newTypeBuilder.CreateType(); delegateInterfaceCache[delegateType] = delegateInterfaceType; } } delegateInterfaceMethod = delegateInterfaceType.GetMethod("Invoke"); return delegateInterfaceType; } private static ProxyGenerator CreateProxyGenerator() { return new ProxyGenerator(); } private class Interceptor : IInterceptor { private ICallInterceptor interceptor; internal Interceptor(ICallInterceptor interceptor) { this.interceptor = interceptor; } public void Intercept(IInvocation invocation) { this.interceptor.Intercept(new CallContext(invocation)); } } private class CallContext : ICallContext { private IInvocation invocation; internal CallContext(IInvocation invocation) { this.invocation = invocation; } public object[] Arguments { get { return this.invocation.Arguments; } } public MethodInfo Method { get { return this.invocation.Method; } } public object ReturnValue { get { return this.invocation.ReturnValue; } set { this.invocation.ReturnValue = value; } } public void InvokeBase() { this.invocation.Proceed(); } public void SetArgumentValue(int index, object value) { this.invocation.SetArgumentValue(index, value); } } }
ProxyGenerator就是Castle的一个DynamicProxy的实现,CreateInterfaceProxyWithoutTarget和CreateClassProxy有好多重载的方法
#region CreateInterfaceProxyWithoutTarget /// <summary> /// Creates proxy object intercepting calls to members of interface <typeparamref name="TInterface"/> on target object generated at runtime with given <paramref name="interceptor"/>. /// </summary> /// <typeparam name="TInterface">Type of the interface which will be proxied.</typeparam> /// <param name="interceptor">The interceptors called during the invocation of proxied methods.</param> /// <returns> /// Object proxying calls to members of <typeparamref name="TInterface"/> types on generated target object. /// </returns> /// <exception cref="ArgumentNullException">Thrown when given <paramref name="interceptor"/> array is a null reference (Nothing in Visual Basic).</exception> /// <exception cref="ArgumentException">Thrown when given <typeparamref name="TInterface"/> is not an interface type.</exception> /// <remarks> /// Since this method uses an empty-shell implementation of interfaces to proxy generated at runtime, the actual implementation of proxied methods must be provided by given <see cref="IInterceptor"/> implementations. /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call <see cref="IInvocation.Proceed"/>, since there's no actual implementation to proceed with. /// As a result of that also at least one <see cref="IInterceptor"/> implementation must be provided. /// This method uses <see cref="IProxyBuilder"/> implementation to generate a proxy type. /// As such caller should expect any type of exception that given <see cref="IProxyBuilder"/> implementation may throw. /// </remarks> public TInterface CreateInterfaceProxyWithoutTarget<TInterface>(IInterceptor interceptor) where TInterface : class { return (TInterface)CreateInterfaceProxyWithoutTarget(typeof(TInterface), interceptor); } /// <summary> /// Creates proxy object intercepting calls to members of interface <typeparamref name="TInterface"/> on target object generated at runtime with given <paramref name="interceptors"/>. /// </summary> /// <typeparam name="TInterface">Type of the interface which will be proxied.</typeparam> /// <param name="interceptors">The interceptors called during the invocation of proxied methods.</param> /// <returns> /// Object proxying calls to members of <typeparamref name="TInterface"/> types on generated target object. /// </returns> /// <exception cref="ArgumentNullException">Thrown when given <paramref name="interceptors"/> array is a null reference (Nothing in Visual Basic).</exception> /// <exception cref="ArgumentException">Thrown when given <typeparamref name="TInterface"/> is not an interface type.</exception> /// <remarks> /// Since this method uses an empty-shell implementation of interfaces to proxy generated at runtime, the actual implementation of proxied methods must be provided by given <see cref="IInterceptor"/> implementations. /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call <see cref="IInvocation.Proceed"/>, since there's no actual implementation to proceed with. /// As a result of that also at least one <see cref="IInterceptor"/> implementation must be provided. /// This method uses <see cref="IProxyBuilder"/> implementation to generate a proxy type. /// As such caller should expect any type of exception that given <see cref="IProxyBuilder"/> implementation may throw. /// </remarks> public TInterface CreateInterfaceProxyWithoutTarget<TInterface>(params IInterceptor[] interceptors) where TInterface : class { return (TInterface)CreateInterfaceProxyWithoutTarget(typeof(TInterface), interceptors); } /// <summary> /// Creates proxy object intercepting calls to members of interface <typeparamref name="TInterface"/> on target object generated at runtime with given <paramref name="interceptors"/>. /// </summary> /// <typeparam name="TInterface">Type of the interface which will be proxied.</typeparam> /// <param name="options">The proxy generation options used to influence generated proxy type and object.</param> /// <param name="interceptors">The interceptors called during the invocation of proxied methods.</param> /// <returns> /// Object proxying calls to members of <typeparamref name="TInterface"/> types on generated target object. /// </returns> /// <exception cref="ArgumentNullException">Thrown when given <paramref name="interceptors"/> array is a null reference (Nothing in Visual Basic).</exception> /// <exception cref="ArgumentException">Thrown when given <typeparamref name="TInterface"/> is not an interface type.</exception> /// <remarks> /// Since this method uses an empty-shell implementation of interfaces to proxy generated at runtime, the actual implementation of proxied methods must be provided by given <see cref="IInterceptor"/> implementations. /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call <see cref="IInvocation.Proceed"/>, since there's no actual implementation to proceed with. /// As a result of that also at least one <see cref="IInterceptor"/> implementation must be provided. /// This method uses <see cref="IProxyBuilder"/> implementation to generate a proxy type. /// As such caller should expect any type of exception that given <see cref="IProxyBuilder"/> implementation may throw. /// </remarks> public TInterface CreateInterfaceProxyWithoutTarget<TInterface>(ProxyGenerationOptions options, params IInterceptor[] interceptors) where TInterface : class { return (TInterface)CreateInterfaceProxyWithoutTarget(typeof(TInterface), Type.EmptyTypes, options, interceptors); } /// <summary> /// Creates proxy object intercepting calls to members of interface <paramref name="interfaceToProxy"/> on target object generated at runtime with given <paramref name="interceptor"/>. /// </summary> /// <param name="interfaceToProxy">Type of the interface which will be proxied.</param> /// <param name="interceptor">The interceptors called during the invocation of proxied methods.</param> /// <returns> /// Object proxying calls to members of <paramref name="interfaceToProxy"/> type on generated target object. /// </returns> /// <exception cref="ArgumentNullException">Thrown when given <paramref name="interfaceToProxy"/> object is a null reference (Nothing in Visual Basic).</exception> /// <exception cref="ArgumentNullException">Thrown when given <paramref name="interceptor"/> array is a null reference (Nothing in Visual Basic).</exception> /// <exception cref="ArgumentException">Thrown when given <paramref name="interfaceToProxy"/> is a generic type definition.</exception> /// <exception cref="ArgumentException">Thrown when given <paramref name="interfaceToProxy"/> is not an interface type.</exception> /// <remarks> /// Since this method uses an empty-shell implementation of interfaces to proxy generated at runtime, the actual implementation of proxied methods must be provided by given <see cref="IInterceptor"/> implementations. /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call <see cref="IInvocation.Proceed"/>, since there's no actual implementation to proceed with. /// This method uses <see cref="IProxyBuilder"/> implementation to generate a proxy type. /// As such caller should expect any type of exception that given <see cref="IProxyBuilder"/> implementation may throw. /// </remarks> public object CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, IInterceptor interceptor) { return CreateInterfaceProxyWithoutTarget(interfaceToProxy, Type.EmptyTypes, ProxyGenerationOptions.Default, interceptor); } /// <summary> /// Creates proxy object intercepting calls to members of interface <paramref name="interfaceToProxy"/> on target object generated at runtime with given <paramref name="interceptors"/>. /// </summary> /// <param name="interfaceToProxy">Type of the interface which will be proxied.</param> /// <param name="interceptors">The interceptors called during the invocation of proxied methods.</param> /// <returns> /// Object proxying calls to members of <paramref name="interfaceToProxy"/> type on generated target object. /// </returns> /// <exception cref="ArgumentNullException">Thrown when given <paramref name="interfaceToProxy"/> object is a null reference (Nothing in Visual Basic).</exception> /// <exception cref="ArgumentNullException">Thrown when given <paramref name="interceptors"/> array is a null reference (Nothing in Visual Basic).</exception> /// <exception cref="ArgumentException">Thrown when given <paramref name="interfaceToProxy"/> is a generic type definition.</exception> /// <exception cref="ArgumentException">Thrown when given <paramref name="interfaceToProxy"/> is not an interface type.</exception> /// <remarks> /// Since this method uses an empty-shell implementation of interfaces to proxy generated at runtime, the actual implementation of proxied methods must be provided by given <see cref="IInterceptor"/> implementations. /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call <see cref="IInvocation.Proceed"/>, since there's no actual implementation to proceed with. /// This method uses <see cref="IProxyBuilder"/> implementation to generate a proxy type. /// As such caller should expect any type of exception that given <see cref="IProxyBuilder"/> implementation may throw. /// </remarks> public object CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, params IInterceptor[] interceptors) { return CreateInterfaceProxyWithoutTarget(interfaceToProxy, Type.EmptyTypes, ProxyGenerationOptions.Default, interceptors); } /// <summary> /// Creates proxy object intercepting calls to members of interface <paramref name="interfaceToProxy"/> on target object generated at runtime with given <paramref name="interceptors"/>. /// </summary> /// <param name="interfaceToProxy">Type of the interface which will be proxied.</param> /// <param name="additionalInterfacesToProxy">Additional interface types. Calls to their members will be proxied as well.</param> /// <param name="interceptors">The interceptors called during the invocation of proxied methods.</param> /// <returns> /// Object proxying calls to members of <paramref name="interfaceToProxy"/> and <paramref name="additionalInterfacesToProxy"/> types on generated target object. /// </returns> /// <exception cref="ArgumentNullException">Thrown when given <paramref name="interfaceToProxy"/> object is a null reference (Nothing in Visual Basic).</exception> /// <exception cref="ArgumentNullException">Thrown when given <paramref name="interceptors"/> array is a null reference (Nothing in Visual Basic).</exception> /// <exception cref="ArgumentException">Thrown when given <paramref name="interfaceToProxy"/> or any of <paramref name="additionalInterfacesToProxy"/> is a generic type definition.</exception> /// <exception cref="ArgumentException">Thrown when given <paramref name="interfaceToProxy"/> is not an interface type.</exception> /// <remarks> /// Since this method uses an empty-shell implementation of interfaces to proxy generated at runtime, the actual implementation of proxied methods must be provided by given <see cref="IInterceptor"/> implementations. /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call <see cref="IInvocation.Proceed"/>, since there's no actual implementation to proceed with. /// This method uses <see cref="IProxyBuilder"/> implementation to generate a proxy type. /// As such caller should expect any type of exception that given <see cref="IProxyBuilder"/> implementation may throw. /// </remarks> public object CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, params IInterceptor[] interceptors) { return CreateInterfaceProxyWithoutTarget(interfaceToProxy, additionalInterfacesToProxy, ProxyGenerationOptions.Default, interceptors); } /// <summary> /// Creates proxy object intercepting calls to members of interface <paramref name="interfaceToProxy"/> on target object generated at runtime with given <paramref name="interceptors"/>. /// </summary> /// <param name="interfaceToProxy">Type of the interface which will be proxied.</param> /// <param name="options">The proxy generation options used to influence generated proxy type and object.</param> /// <param name="interceptors">The interceptors called during the invocation of proxied methods.</param> /// <returns> /// Object proxying calls to members of <paramref name="interfaceToProxy"/> on generated target object. /// </returns> /// <exception cref="ArgumentNullException">Thrown when given <paramref name="interfaceToProxy"/> object is a null reference (Nothing in Visual Basic).</exception> /// <exception cref="ArgumentNullException">Thrown when given <paramref name="interceptors"/> array is a null reference (Nothing in Visual Basic).</exception> /// <exception cref="ArgumentException">Thrown when given <paramref name="interfaceToProxy"/> is a generic type definition.</exception> /// <exception cref="ArgumentException">Thrown when given <paramref name="interfaceToProxy"/> is not an interface type.</exception> /// <remarks> /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call <see cref="IInvocation.Proceed"/>, since there's no actual implementation to proceed with. /// This method uses <see cref="IProxyBuilder"/> implementation to generate a proxy type. /// As such caller should expect any type of exception that given <see cref="IProxyBuilder"/> implementation may throw. /// </remarks> public object CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, ProxyGenerationOptions options, params IInterceptor[] interceptors) { return CreateInterfaceProxyWithoutTarget(interfaceToProxy, Type.EmptyTypes, options, interceptors); } /// <summary> /// Creates proxy object intercepting calls to members of interface <paramref name="interfaceToProxy"/> on target object generated at runtime with given <paramref name="interceptors"/>. /// </summary> /// <param name="interfaceToProxy">Type of the interface which will be proxied.</param> /// <param name="options">The proxy generation options used to influence generated proxy type and object.</param> /// <param name="additionalInterfacesToProxy">Additional interface types. Calls to their members will be proxied as well.</param> /// <param name="interceptors">The interceptors called during the invocation of proxied methods.</param> /// <returns> /// Object proxying calls to members of <paramref name="interfaceToProxy"/> and <paramref name="additionalInterfacesToProxy"/> types on generated target object. /// </returns> /// <exception cref="ArgumentNullException">Thrown when given <paramref name="interfaceToProxy"/> object is a null reference (Nothing in Visual Basic).</exception> /// <exception cref="ArgumentNullException">Thrown when given <paramref name="interceptors"/> array is a null reference (Nothing in Visual Basic).</exception> /// <exception cref="ArgumentException">Thrown when given <paramref name="interfaceToProxy"/> or any of <paramref name="additionalInterfacesToProxy"/> is a generic type definition.</exception> /// <exception cref="ArgumentException">Thrown when given <paramref name="interfaceToProxy"/> is not an interface type.</exception> /// <remarks> /// Since this method uses an empty-shell implementation of <paramref name="additionalInterfacesToProxy"/> to proxy generated at runtime, the actual implementation of proxied methods must be provided by given <see cref="IInterceptor"/> implementations. /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call <see cref="IInvocation.Proceed"/>, since there's no actual implementation to proceed with. /// This method uses <see cref="IProxyBuilder"/> implementation to generate a proxy type. /// As such caller should expect any type of exception that given <see cref="IProxyBuilder"/> implementation may throw. /// </remarks> public object CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, params IInterceptor[] interceptors) { if (interfaceToProxy == null) { throw new ArgumentNullException("interfaceToProxy"); } if (interceptors == null) { throw new ArgumentNullException("interceptors"); } if (!interfaceToProxy.IsInterface) { throw new ArgumentException("Specified type is not an interface", "interfaceToProxy"); } CheckNotGenericTypeDefinition(interfaceToProxy, "interfaceToProxy"); CheckNotGenericTypeDefinitions(additionalInterfacesToProxy, "additionalInterfacesToProxy"); Type generatedType = CreateInterfaceProxyTypeWithoutTarget(interfaceToProxy, additionalInterfacesToProxy, options); List<object> arguments = GetConstructorArguments(new object(), interceptors, options); return Activator.CreateInstance(generatedType, arguments.ToArray()); } #endregion
#region CreateClassProxy /// <summary> /// Creates proxy object intercepting calls to virtual members of type <typeparamref name="TClass"/> on newly created instance of that type with given <paramref name="interceptors"/>. /// </summary> /// <typeparam name="TClass">Type of class which will be proxied.</typeparam> /// <param name="interceptors">The interceptors called during the invocation of proxied methods.</param> /// <returns> /// New object of type <typeparamref name="TClass"/> proxying calls to virtual members of <typeparamref name="TClass"/> type. /// </returns> /// <exception cref="ArgumentException">Thrown when given <typeparamref name="TClass"/> is not a class type.</exception> /// <exception cref="ArgumentException">Thrown when no default constructor exists on type <typeparamref name="TClass"/>.</exception> /// <exception cref="TargetInvocationException">Thrown when default constructor of type <typeparamref name="TClass"/> throws an exception.</exception> /// <remarks> /// This method uses <see cref="IProxyBuilder"/> implementation to generate a proxy type. /// As such caller should expect any type of exception that given <see cref="IProxyBuilder"/> implementation may throw. /// </remarks> public TClass CreateClassProxy<TClass>(params IInterceptor[] interceptors) where TClass : class { return (TClass) CreateClassProxy(typeof(TClass), ProxyGenerationOptions.Default, interceptors); } /// <summary> /// Creates proxy object intercepting calls to virtual members of type <typeparamref name="TClass"/> on newly created instance of that type with given <paramref name="interceptors"/>. /// </summary> /// <typeparam name="TClass">Type of class which will be proxied.</typeparam> /// <param name="options">The proxy generation options used to influence generated proxy type and object.</param> /// <param name="interceptors">The interceptors called during the invocation of proxied methods.</param> /// <returns> /// New object of type <typeparamref name="TClass"/> proxying calls to virtual members of <typeparamref name="TClass"/> type. /// </returns> /// <exception cref="ArgumentException">Thrown when given <typeparamref name="TClass"/> is not a class type.</exception> /// <exception cref="ArgumentException">Thrown when no default constructor exists on type <typeparamref name="TClass"/>.</exception> /// <exception cref="TargetInvocationException">Thrown when default constructor of type <typeparamref name="TClass"/> throws an exception.</exception> /// <remarks> /// This method uses <see cref="IProxyBuilder"/> implementation to generate a proxy type. /// As such caller should expect any type of exception that given <see cref="IProxyBuilder"/> implementation may throw. /// </remarks> public TClass CreateClassProxy<TClass>(ProxyGenerationOptions options, params IInterceptor[] interceptors) where TClass : class { return (TClass)CreateClassProxy(typeof(TClass), options, interceptors); } /// <summary> /// Creates proxy object intercepting calls to virtual members of type <paramref name="classToProxy"/> on newly created instance of that type with given <paramref name="interceptors"/>. /// </summary> /// <param name="classToProxy">Type of class which will be proxied.</param> /// <param name="additionalInterfacesToProxy">Additional interface types. Calls to their members will be proxied as well.</param> /// <param name="interceptors">The interceptors called during the invocation of proxied methods.</param> /// <returns> /// New object of type <paramref name="classToProxy"/> proxying calls to virtual members of <paramref name="classToProxy"/> and <paramref name="additionalInterfacesToProxy"/> types. /// </returns> /// <exception cref="ArgumentNullException">Thrown when given <paramref name="classToProxy"/> object is a null reference (Nothing in Visual Basic).</exception> /// <exception cref="ArgumentException">Thrown when given <paramref name="classToProxy"/> or any of <paramref name="additionalInterfacesToProxy"/> is a generic type definition.</exception> /// <exception cref="ArgumentException">Thrown when given <paramref name="classToProxy"/> is not a class type.</exception> /// <exception cref="ArgumentException">Thrown when no default constructor exists on type <paramref name="classToProxy"/>.</exception> /// <exception cref="TargetInvocationException">Thrown when default constructor of type <paramref name="classToProxy"/> throws an exception.</exception> /// <remarks> /// This method uses <see cref="IProxyBuilder"/> implementation to generate a proxy type. /// As such caller should expect any type of exception that given <see cref="IProxyBuilder"/> implementation may throw. /// </remarks> public object CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, params IInterceptor[] interceptors) { return CreateClassProxy(classToProxy, additionalInterfacesToProxy, ProxyGenerationOptions.Default, interceptors); } /// <summary> /// Creates proxy object intercepting calls to virtual members of type <paramref name="classToProxy"/> on newly created instance of that type with given <paramref name="interceptors"/>. /// </summary> /// <param name="classToProxy">Type of class which will be proxied.</param> /// <param name="constructorArguments">Arguments of constructor of type <paramref name="classToProxy"/> which should be used to create a new instance of that type.</param> /// <param name="interceptors">The interceptors called during the invocation of proxied methods.</param> /// <returns> /// New object of type <paramref name="classToProxy"/> proxying calls to virtual members of <paramref name="classToProxy"/> type. /// </returns> /// <exception cref="ArgumentNullException">Thrown when given <paramref name="classToProxy"/> object is a null reference (Nothing in Visual Basic).</exception> /// <exception cref="ArgumentException">Thrown when given <paramref name="classToProxy"/> is a generic type definition.</exception> /// <exception cref="ArgumentException">Thrown when given <paramref name="classToProxy"/> is not a class type.</exception> /// <exception cref="ArgumentException">Thrown when no constructor exists on type <paramref name="classToProxy"/> with parameters matching <paramref name="constructorArguments"/>.</exception> /// <exception cref="TargetInvocationException">Thrown when constructor of type <paramref name="classToProxy"/> throws an exception.</exception> /// <remarks> /// This method uses <see cref="IProxyBuilder"/> implementation to generate a proxy type. /// As such caller should expect any type of exception that given <see cref="IProxyBuilder"/> implementation may throw. /// </remarks> [Obsolete("This method has been made obsolete due to issues with passing constructor arguments as 'params' array. Use other overload that passes constructor arguments as an explicit array.")] public object CreateClassProxy(Type classToProxy, IInterceptor[] interceptors, params object[] constructorArguments) { return CreateClassProxy(classToProxy, null, ProxyGenerationOptions.Default, constructorArguments, interceptors); } /// <summary> /// Creates proxy object intercepting calls to virtual members of type <paramref name="classToProxy"/> on newly created instance of that type with given <paramref name="interceptors"/>. /// </summary> /// <param name="classToProxy">Type of class which will be proxied.</param> /// <param name="options">The proxy generation options used to influence generated proxy type and object.</param> /// <param name="constructorArguments">Arguments of constructor of type <paramref name="classToProxy"/> which should be used to create a new instance of that type.</param> /// <param name="interceptors">The interceptors called during the invocation of proxied methods.</param> /// <returns> /// New object of type <paramref name="classToProxy"/> proxying calls to virtual members of <paramref name="classToProxy"/> type. /// </returns> /// <exception cref="ArgumentNullException">Thrown when given <paramref name="classToProxy"/> object is a null reference (Nothing in Visual Basic).</exception> /// <exception cref="ArgumentException">Thrown when given <paramref name="classToProxy"/> is a generic type definition.</exception> /// <exception cref="ArgumentException">Thrown when given <paramref name="classToProxy"/> is not a class type.</exception> /// <exception cref="ArgumentException">Thrown when no constructor exists on type <paramref name="classToProxy"/> with parameters matching <paramref name="constructorArguments"/>.</exception> /// <exception cref="TargetInvocationException">Thrown when constructor of type <paramref name="classToProxy"/> throws an exception.</exception> /// <remarks> /// This method uses <see cref="IProxyBuilder"/> implementation to generate a proxy type. /// As such caller should expect any type of exception that given <see cref="IProxyBuilder"/> implementation may throw. /// </remarks> public object CreateClassProxy(Type classToProxy, ProxyGenerationOptions options, object[] constructorArguments, params IInterceptor[] interceptors) { return CreateClassProxy(classToProxy, null, options, constructorArguments, interceptors); } /// <summary> /// Creates proxy object intercepting calls to virtual members of type <paramref name="classToProxy"/> on newly created instance of that type with given <paramref name="interceptors"/>. /// </summary> /// <param name="classToProxy">Type of class which will be proxied.</param> /// <param name="constructorArguments">Arguments of constructor of type <paramref name="classToProxy"/> which should be used to create a new instance of that type.</param> /// <param name="interceptors">The interceptors called during the invocation of proxied methods.</param> /// <returns> /// New object of type <paramref name="classToProxy"/> proxying calls to virtual members of <paramref name="classToProxy"/> type. /// </returns> /// <exception cref="ArgumentNullException">Thrown when given <paramref name="classToProxy"/> object is a null reference (Nothing in Visual Basic).</exception> /// <exception cref="ArgumentException">Thrown when given <paramref name="classToProxy"/> is a generic type definition.</exception> /// <exception cref="ArgumentException">Thrown when given <paramref name="classToProxy"/> is not a class type.</exception> /// <exception cref="ArgumentException">Thrown when no constructor exists on type <paramref name="classToProxy"/> with parameters matching <paramref name="constructorArguments"/>.</exception> /// <exception cref="TargetInvocationException">Thrown when constructor of type <paramref name="classToProxy"/> throws an exception.</exception> /// <remarks> /// This method uses <see cref="IProxyBuilder"/> implementation to generate a proxy type. /// As such caller should expect any type of exception that given <see cref="IProxyBuilder"/> implementation may throw. /// </remarks> public object CreateClassProxy(Type classToProxy, object[] constructorArguments, params IInterceptor[] interceptors) { return CreateClassProxy(classToProxy, null, ProxyGenerationOptions.Default, constructorArguments, interceptors); } /// <summary> /// Creates proxy object intercepting calls to virtual members of type <paramref name="classToProxy"/> on newly created instance of that type with given <paramref name="interceptors"/>. /// </summary> /// <param name="classToProxy">Type of class which will be proxied.</param> /// <param name="interceptors">The interceptors called during the invocation of proxied methods.</param> /// <returns> /// New object of type <paramref name="classToProxy"/> proxying calls to virtual members of <paramref name="classToProxy"/> type. /// </returns> /// <exception cref="ArgumentNullException">Thrown when given <paramref name="classToProxy"/> object is a null reference (Nothing in Visual Basic).</exception> /// <exception cref="ArgumentException">Thrown when given <paramref name="classToProxy"/> is a generic type definition.</exception> /// <exception cref="ArgumentException">Thrown when given <paramref name="classToProxy"/> is not a class type.</exception> /// <exception cref="ArgumentException">Thrown when no parameterless constructor exists on type <paramref name="classToProxy"/>.</exception> /// <exception cref="TargetInvocationException">Thrown when constructor of type <paramref name="classToProxy"/> throws an exception.</exception> /// <remarks> /// This method uses <see cref="IProxyBuilder"/> implementation to generate a proxy type. /// As such caller should expect any type of exception that given <see cref="IProxyBuilder"/> implementation may throw. /// </remarks> public object CreateClassProxy(Type classToProxy, params IInterceptor[] interceptors) { return CreateClassProxy(classToProxy, null, ProxyGenerationOptions.Default, null, interceptors); } /// <summary> /// Creates proxy object intercepting calls to virtual members of type <paramref name="classToProxy"/> on newly created instance of that type with given <paramref name="interceptors"/>. /// </summary> /// <param name="classToProxy">Type of class which will be proxied.</param> /// <param name="options">The proxy generation options used to influence generated proxy type and object.</param> /// <param name="interceptors">The interceptors called during the invocation of proxied methods.</param> /// <returns> /// New object of type <paramref name="classToProxy"/> proxying calls to virtual members of <paramref name="classToProxy"/> type. /// </returns> /// <exception cref="ArgumentNullException">Thrown when given <paramref name="classToProxy"/> object is a null reference (Nothing in Visual Basic).</exception> /// <exception cref="ArgumentNullException">Thrown when given <paramref name="options"/> object is a null reference (Nothing in Visual Basic).</exception> /// <exception cref="ArgumentException">Thrown when given <paramref name="classToProxy"/> is a generic type definition.</exception> /// <exception cref="ArgumentException">Thrown when given <paramref name="classToProxy"/> is not a class type.</exception> /// <exception cref="ArgumentException">Thrown when no default constructor exists on type <paramref name="classToProxy"/>.</exception> /// <exception cref="TargetInvocationException">Thrown when default constructor of type <paramref name="classToProxy"/> throws an exception.</exception> /// <remarks> /// This method uses <see cref="IProxyBuilder"/> implementation to generate a proxy type. /// As such caller should expect any type of exception that given <see cref="IProxyBuilder"/> implementation may throw. /// </remarks> public object CreateClassProxy(Type classToProxy, ProxyGenerationOptions options, params IInterceptor[] interceptors) { return CreateClassProxy(classToProxy, null, options, interceptors); } /// <summary> /// Creates proxy object intercepting calls to virtual members of type <paramref name="classToProxy"/> on newly created instance of that type with given <paramref name="interceptors"/>. /// </summary> /// <param name="classToProxy">Type of class which will be proxied.</param> /// <param name="additionalInterfacesToProxy">Additional interface types. Calls to their members will be proxied as well.</param> /// <param name="options">The proxy generation options used to influence generated proxy type and object.</param> /// <param name="interceptors">The interceptors called during the invocation of proxied methods.</param> /// <returns> /// New object of type <paramref name="classToProxy"/> proxying calls to virtual members of <paramref name="classToProxy"/> and <paramref name="additionalInterfacesToProxy"/> types. /// </returns> /// <exception cref="ArgumentNullException">Thrown when given <paramref name="classToProxy"/> object is a null reference (Nothing in Visual Basic).</exception> /// <exception cref="ArgumentNullException">Thrown when given <paramref name="options"/> object is a null reference (Nothing in Visual Basic).</exception> /// <exception cref="ArgumentException">Thrown when given <paramref name="classToProxy"/> or any of <paramref name="additionalInterfacesToProxy"/> is a generic type definition.</exception> /// <exception cref="ArgumentException">Thrown when given <paramref name="classToProxy"/> is not a class type.</exception> /// <exception cref="ArgumentException">Thrown when no default constructor exists on type <paramref name="classToProxy"/>.</exception> /// <exception cref="TargetInvocationException">Thrown when default constructor of type <paramref name="classToProxy"/> throws an exception.</exception> /// <remarks> /// This method uses <see cref="IProxyBuilder"/> implementation to generate a proxy type. /// As such caller should expect any type of exception that given <see cref="IProxyBuilder"/> implementation may throw. /// </remarks> public object CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, params IInterceptor[] interceptors) { return CreateClassProxy(classToProxy, additionalInterfacesToProxy, options, null, interceptors); } /// <summary> /// Creates proxy object intercepting calls to virtual members of type <paramref name="classToProxy"/> on newly created instance of that type with given <paramref name="interceptors"/>. /// </summary> /// <param name="classToProxy">Type of class which will be proxied.</param> /// <param name="additionalInterfacesToProxy">Additional interface types. Calls to their members will be proxied as well.</param> /// <param name="options">The proxy generation options used to influence generated proxy type and object.</param> /// <param name="constructorArguments">Arguments of constructor of type <paramref name="classToProxy"/> which should be used to create a new instance of that type.</param> /// <param name="interceptors">The interceptors called during the invocation of proxied methods.</param> /// <returns> /// New object of type <paramref name="classToProxy"/> proxying calls to virtual members of <paramref name="classToProxy"/> and <paramref name="additionalInterfacesToProxy"/> types. /// </returns> /// <exception cref="ArgumentNullException">Thrown when given <paramref name="classToProxy"/> object is a null reference (Nothing in Visual Basic).</exception> /// <exception cref="ArgumentNullException">Thrown when given <paramref name="options"/> object is a null reference (Nothing in Visual Basic).</exception> /// <exception cref="ArgumentException">Thrown when given <paramref name="classToProxy"/> or any of <paramref name="additionalInterfacesToProxy"/> is a generic type definition.</exception> /// <exception cref="ArgumentException">Thrown when given <paramref name="classToProxy"/> is not a class type.</exception> /// <exception cref="ArgumentException">Thrown when no constructor exists on type <paramref name="classToProxy"/> with parameters matching <paramref name="constructorArguments"/>.</exception> /// <exception cref="TargetInvocationException">Thrown when constructor of type <paramref name="classToProxy"/> throws an exception.</exception> /// <remarks> /// This method uses <see cref="IProxyBuilder"/> implementation to generate a proxy type. /// As such caller should expect any type of exception that given <see cref="IProxyBuilder"/> implementation may throw. /// </remarks> public object CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, object[] constructorArguments, params IInterceptor[] interceptors) { if (classToProxy == null) { throw new ArgumentNullException("classToProxy"); } if (options == null) { throw new ArgumentNullException("options"); } if (!classToProxy.IsClass) { throw new ArgumentException("'classToProxy' must be a class", "classToProxy"); } CheckNotGenericTypeDefinition(classToProxy, "classToProxy"); CheckNotGenericTypeDefinitions(additionalInterfacesToProxy, "additionalInterfacesToProxy"); Type proxyType = CreateClassProxyType(classToProxy, additionalInterfacesToProxy, options); // create constructor arguments (initialized with mixin implementations, interceptors and target type constructor arguments) List<object> arguments = BuildArgumentListForClassProxy(options, interceptors); if (constructorArguments != null && constructorArguments.Length != 0) { arguments.AddRange(constructorArguments); } return CreateClassProxyInstance(proxyType, arguments, classToProxy, constructorArguments); } private object CreateClassProxyInstance(Type proxyType, List<object> proxyArguments, Type classToProxy, object[] constructorArguments) { try { return Activator.CreateInstance(proxyType, proxyArguments.ToArray()); } catch (MissingMethodException) { var message = new StringBuilder(); message.AppendFormat("Can not instantiate proxy of class: {0}.", classToProxy.FullName); message.AppendLine(); if (constructorArguments == null || constructorArguments.Length == 0) { message.Append("Could not find a parameterless constructor."); } else { message.AppendLine("Could not find a constructor that would match given arguments:"); foreach(var argument in constructorArguments) { message.AppendLine(argument.GetType().ToString()); } } throw new ArgumentException(message.ToString(), "constructorArguments"); } } private List<object> BuildArgumentListForClassProxy(ProxyGenerationOptions options, IInterceptor[] interceptors) { var arguments = new List<object>(options.MixinData.Mixins) { interceptors }; if (options.Selector != null) { arguments.Add(options.Selector); } return arguments; } #endregion /// <summary> /// Creates the proxy type for class proxy with given <paramref name="classToProxy"/> class, implementing given <paramref name="additionalInterfacesToProxy"/> and using provided <paramref name="options"/>. /// </summary> /// <param name="classToProxy">The base class for proxy type.</param> /// <param name="additionalInterfacesToProxy">The interfaces that proxy type should implement.</param> /// <param name="options">The options for proxy generation process.</param> /// <returns><see cref="Type"/> of proxy.</returns> protected Type CreateClassProxyType(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options) { // create proxy return ProxyBuilder.CreateClassProxyType(classToProxy, additionalInterfacesToProxy, options); } /// <summary> /// Creates the proxy type for interface proxy with target for given <paramref name="interfaceToProxy"/> interface, implementing given <paramref name="additionalInterfacesToProxy"/> on given <paramref name="targetType"/> and using provided <paramref name="options"/>. /// </summary> /// <param name="interfaceToProxy">The interface proxy type should implement.</param> /// <param name="additionalInterfacesToProxy">The additional interfaces proxy type should implement.</param> /// <param name="targetType">Actual type that the proxy type will encompass.</param> /// <param name="options">The options for proxy generation process.</param> /// <returns><see cref="Type"/> of proxy.</returns> protected Type CreateInterfaceProxyTypeWithTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, Type targetType, ProxyGenerationOptions options) { // create proxy return ProxyBuilder.CreateInterfaceProxyTypeWithTarget(interfaceToProxy, additionalInterfacesToProxy, targetType, options); } /// <summary> /// Creates the proxy type for interface proxy with target interface for given <paramref name="interfaceToProxy"/> interface, implementing given <paramref name="additionalInterfacesToProxy"/> on given <paramref name="targetType"/> and using provided <paramref name="options"/>. /// </summary> /// <param name="interfaceToProxy">The interface proxy type should implement.</param> /// <param name="additionalInterfacesToProxy">The additional interfaces proxy type should implement.</param> /// <param name="options">The options for proxy generation process.</param> /// <returns><see cref="Type"/> of proxy.</returns> protected Type CreateInterfaceProxyTypeWithTargetInterface(Type interfaceToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options) { // create proxy return ProxyBuilder.CreateInterfaceProxyTypeWithTargetInterface(interfaceToProxy, additionalInterfacesToProxy, options); } /// <summary> /// Creates the proxy type for interface proxy without target for given <paramref name="interfaceToProxy"/> interface, implementing given <paramref name="additionalInterfacesToProxy"/> and using provided <paramref name="options"/>. /// </summary> /// <param name="interfaceToProxy">The interface proxy type should implement.</param> /// <param name="additionalInterfacesToProxy">The additional interfaces proxy type should implement.</param> /// <param name="options">The options for proxy generation process.</param> /// <returns><see cref="Type"/> of proxy.</returns> protected Type CreateInterfaceProxyTypeWithoutTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options) { // create proxy return ProxyBuilder.CreateInterfaceProxyTypeWithoutTarget(interfaceToProxy, additionalInterfacesToProxy, options); }
当你写UT的时候Mock过的方法就会被拦截调用,否则还是调用自己真正的实现。
至于说Castle是通过EMIT的方式创建proxy的,而且和CLR的实现方式有所区别,需要进一步研究。
参考:
http://app-code.net/wordpress/?p=689
https://github.com/moq/moq4
https://github.com/castleproject/Castle.DynamicProxy-READONLY/blob/master/src/Castle.DynamicProxy/ProxyGenerator.cs
https://github.com/castleproject/Core/blob/master/src/Castle.Core/DynamicProxy/IInterceptor.cs