Mock原理学习
同事搓蛋问了我一个问题,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 != )
{
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 == )
{
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
Mock原理学习的更多相关文章
- IIS原理学习
IIS 原理学习 首先声明以下内容是我在网上搜索后整理的,在此只是进行记录,以备往后查阅只用. IIS 5.x介绍 IIS 5.x一个显著的特征就是Web Server和真正的ASP.NET Appl ...
- zookkeper原理学习
zookkeper原理学习 https://segmentfault.com/a/1190000014479433 https://www.cnblogs.com/felixzh/p/58692 ...
- GIS原理学习目录
GIS原理学习目录 内容提要 本网络教程是教育部“新世纪网络课程建设工程”的实施课程.系统扼要地阐述地理信息系统的技术体系,重点突出地理信息系统的基本技术及方法. 本网络教程共分八章:第一章绪论,重点 ...
- 转:SVM与SVR支持向量机原理学习与思考(一)
SVM与SVR支持向量机原理学习与思考(一) 转:http://tonysh-thu.blogspot.com/2009/07/svmsvr.html 弱弱的看了看老掉牙的支持向量机(Support ...
- Android自复制传播APP原理学习(翻译)
Android自复制传播APP原理学习(翻译) 1 背景介绍 论文链接:http://arxiv.org/abs/1511.00444 项目地址:https://github.com/Tribler ...
- 计算机原理学习(1)-- 冯诺依曼体系和CPU工作原理
前言 对于我们80后来说,最早接触计算机应该是在95年左右,那个时候最流行的一个词语是多媒体. 依旧记得当时在同学家看同学输入几个DOS命令就成功的打开了一个游戏,当时实在是佩服的五体投地.因为对我来 ...
- Dubbo原理学习
Dubbo源码及原理学习 阿里中间件团队博客 Dubbo官网 Dubbo源码解析 Dubbo源码解析-掘金 Dubbo源码解析-赵计刚 Dubbo系列 源码总结+最近感悟
- XGBoost原理学习总结
XGBoost原理学习总结 前言 XGBoost是一个上限提别高的机器学习算法,和Adaboost.GBDT等都属于Boosting类集成算法.虽然现在深度学习算法大行其道,但很多数据量往往没有太 ...
- Git原理学习记录
Git原理学习记录 1.git init git-test git init 实际上就是在特定的目录下创建对应的目录和文件 2.object $ echo "V1" > ...
随机推荐
- ASP.NET验证控件
在此过程中房间的收费制度时,.为了验证文本框是否为空.用户存在.合法等等.我们都要单独写代码.学习了ASP.NET的验证控件,省了非常多事. ASP.NET能够轻松实现对用户输入的验证. 让我们好好回 ...
- Ubuntu设置交换空间參考教程[图]
假设你当前使用的Ubuntu系统,不管是虚拟机还是实体机,没有交换分区或交换分区空间不足,能够为其设置交换空间. 本文提供的是一种设置交换空间的简单方法. 如若转载,请注明博文地址及原作者(Risin ...
- 优秀团队建设--美国式团队(ppt)
美国式团队 一.团队精神 团队精神反映一个人的素养.一个人的能力,一个人与别人合作的精神和能力.一个团队是个有机的总体,作为个人,仅仅有全然融入到这个有机总体之中,才干最大限度地体现自己的价值. 团队 ...
- Android 4.4(KitKat)表格管理子系统 - 骨架
原文地址:http://blog.csdn.net/jinzhuojun/article/details/37737439 窗体管理系统是Android中的主要子系统之中的一个.它涉及到App中组件的 ...
- DES加密和解密PHP,Java,ObjectC统一的方法
原文:DES加密和解密PHP,Java,ObjectC统一的方法 PHP的加解密函数 <?php class DesComponent { var $key = '12345678'; func ...
- android在单身的对象和一些数据的问题被释放
正式接触android我们一直在开发了一段时间,该项目的第一个版本最终会很快结束. 当有它自己的测试.拥有android后台.同一时候打开了几个应用之后又一次切回到自己的app.发现报错了.经过排查, ...
- cocos2d-x3.x 设计与实现弹出对话框
要定义一个类PopupLayer 代码PopupLayer.h #ifndef __crossDT_PopupLayer__ #define __crossDT_PopupLayer__ #inclu ...
- Android手游《》斗地主完整的源代码(支持单机和网络对战)
Android手游<斗地主>完整的源代码(支持单机和网络对战)下载.一个很不错的源代码. 斗地主掌游是一个独特的国内社会斗地主棋牌游戏,之后玩家可以下载网上斗地主和全世界.掌游斗地主特点: ...
- linux_sed 正则替换
目标 替换 test.data文件中的 原正则: (\d{4}[^)]*?) sed不支持 \d 改为0-9 测试 :head test.data| sed -r "s/([0-9]{4}[ ...
- 使用ArcGIS API for Silverlight实现地形坡度在线分析
原文:使用ArcGIS API for Silverlight实现地形坡度在线分析 苦逼的研究生课程终于在今天结束了,也许从今以后再也不会坐在大学的课堂上正式的听老师讲课了,接下来的时间就得开始找工作 ...