User: xtoff
Date: 2009/11/14 12:12 PM
Removed:
/DynamicProxy/trunk/src/Castle.DynamicProxy/Generators/
ProxyMethod.cs
Modified:
/DynamicProxy/trunk/lib/mono-3.5/
Castle.Core.dll, Castle.Core.xml
/DynamicProxy/trunk/lib/net-2.0/
Castle.Core.dll, Castle.Core.xml
/DynamicProxy/trunk/lib/net-3.5/
Castle.Core.dll, Castle.Core.xml
/DynamicProxy/trunk/lib/silverlight-2.0/
Castle.Core.dll, Castle.Core.xml
/DynamicProxy/trunk/src/Castle.DynamicProxy/
AbstractInvocation.cs
/DynamicProxy/trunk/src/Castle.DynamicProxy/Generators/
InvocationTypeGenerator.cs
/DynamicProxy/trunk/src/Castle.DynamicProxy/Tokens/
InvocationMethods.cs
Log:
- BREAKING CHANGE - implemented DYNPROXY-ISSUE-91 - Allow
CreateInterfaceProxyWithTargetInterface to be able to permanently change
target. This required adding a method to IChangeProxyTarget interface from
Castle.Core so any code that implements this interface explicitly will not
compile. This is a low-impact change however, since this interface is not
intended to be implemented by users.
File Changes:
Directory: /DynamicProxy/trunk/src/Castle.DynamicProxy/
=======================================================
File [modified]: AbstractInvocation.cs
Delta lines: +41 -10
===================================================================
---
DynamicProxy/trunk/src/Castle.DynamicProxy/Generators/InvocationTypeGenerator.cs
2009-11-14 18:51:50 UTC (rev 6326)
+++
DynamicProxy/trunk/src/Castle.DynamicProxy/Generators/InvocationTypeGenerator.cs
2009-11-14 19:12:50 UTC (rev 6327)
@@ -65,16 +65,7 @@
var targetField = new
FieldReference(InvocationMethods.Target);
if (canChangeTarget)
{
- var argument1 = new ArgumentReference(typeof
(object));
- MethodEmitter methodEmitter =
-
nested.CreateMethod("ChangeInvocationTarget", MethodAttributes.Public |
MethodAttributes.Virtual,
- typeof (void),
argument1);
- methodEmitter.CodeBuilder.AddStatement(
- new AssignStatement(targetField,
- new
ConvertExpression(targetType, argument1.ToExpression())
- )
- );
- methodEmitter.CodeBuilder.AddStatement(new
ReturnStatement());
+ ImplementChangeProxyTargetInterface(@class,
nested, targetField);
}
// InvokeMethodOnTarget implementation
@@ -99,6 +90,46 @@
return nested;
}
+ private void ImplementChangeProxyTargetInterface(ClassEmitter
@class, NestedClassEmitter invocation, FieldReference targetField)
+ {
+ ImplementChangeInvocationTarget(invocation,
targetField);
+
+ ImplementChangeProxyTarget(invocation, @class);
+ }
+
+ private void ImplementChangeProxyTarget(NestedClassEmitter
invocation, ClassEmitter @class)
+ {
+ var argument = new ArgumentReference(typeof(object));
+ var changeInvocationTarget =
invocation.CreateMethod("ChangeProxyTarget",
+
MethodAttributes.Public | MethodAttributes.Virtual,
+
typeof(void),
+
argument);
+ changeInvocationTarget.CodeBuilder.AddStatement(
+ new ExpressionStatement(
+ new
ConvertExpression(@class.TypeBuilder, new
FieldReference(InvocationMethods.ProxyObject).ToExpression())));
+
+ var field = @class.GetField("__target");
+ changeInvocationTarget.CodeBuilder.AddStatement(
+ new AssignStatement(
+ new FieldReference(field.Reference) {
OwnerReference = null },
+ new
ConvertExpression(field.Fieldbuilder.FieldType, argument.ToExpression())));
+
+ changeInvocationTarget.CodeBuilder.AddStatement(new
ReturnStatement());
+ }
+
+ private void ImplementChangeInvocationTarget(NestedClassEmitter
invocation, FieldReference targetField)
+ {
+ var argument = new ArgumentReference(typeof (object));
+ var changeInvocationTarget =
invocation.CreateMethod("ChangeInvocationTarget",
+
MethodAttributes.Public | MethodAttributes.Virtual,
+
typeof(void),
+
argument);
+ changeInvocationTarget.CodeBuilder.AddStatement(
+ new AssignStatement(targetField,
+ new
ConvertExpression(targetType, argument.ToExpression())));
+ changeInvocationTarget.CodeBuilder.AddStatement(new
ReturnStatement());
+ }
+
protected void
CreateIInvocationInvokeOnTarget(NestedClassEmitter nested, ParameterInfo[]
parameters, FieldReference targetField, MethodInfo callbackMethod)
{
Directory: /DynamicProxy/trunk/src/Castle.DynamicProxy/Generators/
==================================================================
File [modified]: InvocationTypeGenerator.cs
Delta lines: +0 -32
===================================================================
--- DynamicProxy/trunk/src/Castle.DynamicProxy/Generators/ProxyMethod.cs
2009-11-14 18:51:50 UTC (rev 6326)
+++ DynamicProxy/trunk/src/Castle.DynamicProxy/Generators/ProxyMethod.cs
2009-11-14 19:12:50 UTC (rev 6327)
@@ -1,32 +0,0 @@
-namespace Castle.DynamicProxy.Generators
-{
- using System.Reflection;
- using Contributors;
-
- public abstract class ProxyMethod : IProxyMethod
- {
- private readonly MethodInfo method;
- private readonly ITypeContributor target;
-
- protected ProxyMethod(MethodInfo method, ITypeContributor
target)
- {
- this.method = method;
- this.target = target;
- }
-
- public MethodInfo Method
- {
- get { return method; }
- }
-
- public bool HasTarget
- {
- get
- {
- return target != null;
- }
- }
-
- public abstract MethodInfo MethodOnTarget { get; }
- }
-}
File [removed]: ProxyMethod.cs
Delta lines: +4 -1
===================================================================
--- DynamicProxy/trunk/src/Castle.DynamicProxy/Tokens/InvocationMethods.cs
2009-11-14 18:51:50 UTC (rev 6326)
+++ DynamicProxy/trunk/src/Castle.DynamicProxy/Tokens/InvocationMethods.cs
2009-11-14 19:12:50 UTC (rev 6327)
@@ -26,12 +26,16 @@
public static readonly FieldInfo Target =
typeof(AbstractInvocation).GetField("target",
BindingFlags.Instance | BindingFlags.NonPublic);
+ public static readonly FieldInfo ProxyObject =
+ typeof(AbstractInvocation).GetField("proxyObject",
BindingFlags.Instance | BindingFlags.NonPublic);
+
public static readonly MethodInfo GetArguments =
typeof(AbstractInvocation).GetMethod("get_Arguments");
public static readonly MethodInfo GetArgumentValue =
typeof(AbstractInvocation).GetMethod("GetArgumentValue");
+
public static readonly MethodInfo GetReturnValue =
typeof(AbstractInvocation).GetMethod("get_ReturnValue");
@@ -62,7 +66,6 @@
new[]
{
typeof(object),
-
typeof(Type),
typeof(object),
Directory: /DynamicProxy/trunk/src/Castle.DynamicProxy/Tokens/
==============================================================
File [modified]: InvocationMethods.cs
Delta lines: +0 -0
===================================================================
Directory: /DynamicProxy/trunk/lib/mono-3.5/
============================================
File [modified]: Castle.Core.dll
Delta lines: None
None
File [modified]: Castle.Core.xml
Delta lines: +33 -0
===================================================================
--- DynamicProxy/trunk/lib/net-2.0/Castle.Core.xml 2009-11-14 18:51:50 UTC
(rev 6326)
+++ DynamicProxy/trunk/lib/net-2.0/Castle.Core.xml 2009-11-14 19:12:50 UTC
(rev 6327)
@@ -239,6 +239,39 @@
it is illegal to return null, and doing so will result in
exception.
</remarks>
</member>
+ <member name="T:Castle.Core.Interceptor.IChangeProxyTarget">
+ <summary>
+ Exposes means to change target objects of proxies and invocations
+ </summary>
+ </member>
+ <member
name="M:Castle.Core.Interceptor.IChangeProxyTarget.ChangeInvocationTarget(System.Object)">
+ <summary>
+ Changes the target object (<see
cref="P:Castle.Core.Interceptor.IInvocation.InvocationTarget"/>) of current
<see cref="T:Castle.Core.Interceptor.IInvocation"/>.
+ </summary>
+ <param name="target">The new value of target of invocation.</param>
+ <remarks>
+ Although the method takes <see cref="T:System.Object"/> the actual
instance must be of type assignable to <see
cref="P:Castle.Core.Interceptor.IInvocation.TargetType"/>, otherwise an <see
cref="T:System.InvalidCastException"/> will be thrown.
+ Also while it's technically legal to pass null reference (Nothing
in Visual Basic) as <paramref name="target"/>, for obvious reasons Dynamic
Proxy will not be able to call the intercepted method on such target.
+ In this case last interceptor in the pipeline mustn't call <see
cref="M:Castle.Core.Interceptor.IInvocation.Proceed"/> or a <see
cref="T:System.NotImplementedException"/> will be throws.
+ Also while it's technically legal to pass proxy itself as
<paramref name="target"/>, this would create stack overflow.
+ In this case last interceptor in the pipeline mustn't call <see
cref="M:Castle.Core.Interceptor.IInvocation.Proceed"/> or a <see
cref="T:System.InvalidOperationException"/> will be throws.
+ </remarks>
+ <exception cref="T:System.InvalidCastException">Thrown when
<paramref name="target"/> is not assignable to the proxied type.</exception>
+ </member>
+ <member
name="M:Castle.Core.Interceptor.IChangeProxyTarget.ChangeProxyTarget(System.Object)">
+ <summary>
+ Permanently changes the target object of the proxy. This does not
affect target of the current invocation.
+ </summary>
+ <param name="target">The new value of target of the proxy.</param>
+ <remarks>
+ Although the method takes <see cref="T:System.Object"/> the actual
instance must be of type assignable to proxy's target type, otherwise an <see
cref="T:System.InvalidCastException"/> will be thrown.
+ Also while it's technically legal to pass null reference (Nothing
in Visual Basic) as <paramref name="target"/>, for obvious reasons Dynamic
Proxy will not be able to call the intercepted method on such target.
+ In this case last interceptor in the pipeline mustn't call <see
cref="M:Castle.Core.Interceptor.IInvocation.Proceed"/> or a <see
cref="T:System.NotImplementedException"/> will be throws.
+ Also while it's technically legal to pass proxy itself as
<paramref name="target"/>, this would create stack overflow.
+ In this case last interceptor in the pipeline mustn't call <see
cref="M:Castle.Core.Interceptor.IInvocation.Proceed"/> or a <see
cref="T:System.InvalidOperationException"/> will be throws.
+ </remarks>
+ <exception cref="T:System.InvalidCastException">Thrown when
<paramref name="target"/> is not assignable to the proxied type.</exception>
+ </member>
<member name="T:Castle.Core.Interceptor.IInterceptor">
<summary>
Directory: /DynamicProxy/trunk/lib/net-2.0/
===========================================
File [modified]: Castle.Core.dll
Delta lines: None
None
File [modified]: Castle.Core.xml
Delta lines: +33 -0
===================================================================
--- DynamicProxy/trunk/lib/net-3.5/Castle.Core.xml 2009-11-14 18:51:50 UTC
(rev 6326)
+++ DynamicProxy/trunk/lib/net-3.5/Castle.Core.xml 2009-11-14 19:12:50 UTC
(rev 6327)
@@ -239,6 +239,39 @@
it is illegal to return null, and doing so will result in
exception.
</remarks>
</member>
+ <member name="T:Castle.Core.Interceptor.IChangeProxyTarget">
+ <summary>
+ Exposes means to change target objects of proxies and invocations
+ </summary>
+ </member>
+ <member
name="M:Castle.Core.Interceptor.IChangeProxyTarget.ChangeInvocationTarget(System.Object)">
+ <summary>
+ Changes the target object (<see
cref="P:Castle.Core.Interceptor.IInvocation.InvocationTarget"/>) of current
<see cref="T:Castle.Core.Interceptor.IInvocation"/>.
+ </summary>
+ <param name="target">The new value of target of invocation.</param>
+ <remarks>
+ Although the method takes <see cref="T:System.Object"/> the actual
instance must be of type assignable to <see
cref="P:Castle.Core.Interceptor.IInvocation.TargetType"/>, otherwise an <see
cref="T:System.InvalidCastException"/> will be thrown.
+ Also while it's technically legal to pass null reference (Nothing
in Visual Basic) as <paramref name="target"/>, for obvious reasons Dynamic
Proxy will not be able to call the intercepted method on such target.
+ In this case last interceptor in the pipeline mustn't call <see
cref="M:Castle.Core.Interceptor.IInvocation.Proceed"/> or a <see
cref="T:System.NotImplementedException"/> will be throws.
+ Also while it's technically legal to pass proxy itself as
<paramref name="target"/>, this would create stack overflow.
+ In this case last interceptor in the pipeline mustn't call <see
cref="M:Castle.Core.Interceptor.IInvocation.Proceed"/> or a <see
cref="T:System.InvalidOperationException"/> will be throws.
+ </remarks>
+ <exception cref="T:System.InvalidCastException">Thrown when
<paramref name="target"/> is not assignable to the proxied type.</exception>
+ </member>
+ <member
name="M:Castle.Core.Interceptor.IChangeProxyTarget.ChangeProxyTarget(System.Object)">
+ <summary>
+ Permanently changes the target object of the proxy. This does not
affect target of the current invocation.
+ </summary>
+ <param name="target">The new value of target of the proxy.</param>
+ <remarks>
+ Although the method takes <see cref="T:System.Object"/> the actual
instance must be of type assignable to proxy's target type, otherwise an <see
cref="T:System.InvalidCastException"/> will be thrown.
+ Also while it's technically legal to pass null reference (Nothing
in Visual Basic) as <paramref name="target"/>, for obvious reasons Dynamic
Proxy will not be able to call the intercepted method on such target.
+ In this case last interceptor in the pipeline mustn't call <see
cref="M:Castle.Core.Interceptor.IInvocation.Proceed"/> or a <see
cref="T:System.NotImplementedException"/> will be throws.
+ Also while it's technically legal to pass proxy itself as
<paramref name="target"/>, this would create stack overflow.
+ In this case last interceptor in the pipeline mustn't call <see
cref="M:Castle.Core.Interceptor.IInvocation.Proceed"/> or a <see
cref="T:System.InvalidOperationException"/> will be throws.
+ </remarks>
+ <exception cref="T:System.InvalidCastException">Thrown when
<paramref name="target"/> is not assignable to the proxied type.</exception>
+ </member>
<member name="T:Castle.Core.Interceptor.IInterceptor">
<summary>
Directory: /DynamicProxy/trunk/lib/net-3.5/
===========================================
File [modified]: Castle.Core.dll
Delta lines: None
None
File [modified]: Castle.Core.xml
Delta lines: +33 -0
===================================================================
--- DynamicProxy/trunk/lib/silverlight-2.0/Castle.Core.xml 2009-11-14
18:51:50 UTC (rev 6326)
+++ DynamicProxy/trunk/lib/silverlight-2.0/Castle.Core.xml 2009-11-14
19:12:50 UTC (rev 6327)
@@ -239,6 +239,39 @@
it is illegal to return null, and doing so will result in
exception.
</remarks>
</member>
+ <member name="T:Castle.Core.Interceptor.IChangeProxyTarget">
+ <summary>
+ Exposes means to change target objects of proxies and invocations
+ </summary>
+ </member>
+ <member
name="M:Castle.Core.Interceptor.IChangeProxyTarget.ChangeInvocationTarget(System.Object)">
+ <summary>
+ Changes the target object (<see
cref="P:Castle.Core.Interceptor.IInvocation.InvocationTarget"/>) of current
<see cref="T:Castle.Core.Interceptor.IInvocation"/>.
+ </summary>
+ <param name="target">The new value of target of invocation.</param>
+ <remarks>
+ Although the method takes <see cref="T:System.Object"/> the actual
instance must be of type assignable to <see
cref="P:Castle.Core.Interceptor.IInvocation.TargetType"/>, otherwise an <see
cref="T:System.InvalidCastException"/> will be thrown.
+ Also while it's technically legal to pass null reference (Nothing
in Visual Basic) as <paramref name="target"/>, for obvious reasons Dynamic
Proxy will not be able to call the intercepted method on such target.
+ In this case last interceptor in the pipeline mustn't call <see
cref="M:Castle.Core.Interceptor.IInvocation.Proceed"/> or a <see
cref="T:System.NotImplementedException"/> will be throws.
+ Also while it's technically legal to pass proxy itself as
<paramref name="target"/>, this would create stack overflow.
+ In this case last interceptor in the pipeline mustn't call <see
cref="M:Castle.Core.Interceptor.IInvocation.Proceed"/> or a <see
cref="T:System.InvalidOperationException"/> will be throws.
+ </remarks>
+ <exception cref="T:System.InvalidCastException">Thrown when
<paramref name="target"/> is not assignable to the proxied type.</exception>
+ </member>
+ <member
name="M:Castle.Core.Interceptor.IChangeProxyTarget.ChangeProxyTarget(System.Object)">
+ <summary>
+ Permanently changes the target object of the proxy. This does not
affect target of the current invocation.
+ </summary>
+ <param name="target">The new value of target of the proxy.</param>
+ <remarks>
+ Although the method takes <see cref="T:System.Object"/> the actual
instance must be of type assignable to proxy's target type, otherwise an <see
cref="T:System.InvalidCastException"/> will be thrown.
+ Also while it's technically legal to pass null reference (Nothing
in Visual Basic) as <paramref name="target"/>, for obvious reasons Dynamic
Proxy will not be able to call the intercepted method on such target.
+ In this case last interceptor in the pipeline mustn't call <see
cref="M:Castle.Core.Interceptor.IInvocation.Proceed"/> or a <see
cref="T:System.NotImplementedException"/> will be throws.
+ Also while it's technically legal to pass proxy itself as
<paramref name="target"/>, this would create stack overflow.
+ In this case last interceptor in the pipeline mustn't call <see
cref="M:Castle.Core.Interceptor.IInvocation.Proceed"/> or a <see
cref="T:System.InvalidOperationException"/> will be throws.
+ </remarks>
+ <exception cref="T:System.InvalidCastException">Thrown when
<paramref name="target"/> is not assignable to the proxied type.</exception>
+ </member>
<member name="T:Castle.Core.Interceptor.IInterceptor">
<summary>
Directory: /DynamicProxy/trunk/lib/silverlight-2.0/
===================================================
File [modified]: Castle.Core.dll
Delta lines: None
None
File [modified]: Castle.Core.xml
Delta lines: +21 -5
===================================================================
--- DynamicProxy/trunk/src/Castle.DynamicProxy/AbstractInvocation.cs
2009-11-14 18:51:50 UTC (rev 6326)
+++ DynamicProxy/trunk/src/Castle.DynamicProxy/AbstractInvocation.cs
2009-11-14 19:12:50 UTC (rev 6327)
@@ -27,7 +27,6 @@
public abstract class AbstractInvocation : IInvocation, ISerializable
#endif
{
- private readonly object proxy;
private readonly IInterceptor[] interceptors;
private readonly MethodInfo proxiedMethod;
private readonly object[] arguments;
@@ -35,6 +34,7 @@
private object returnValue;
private int execIndex = -1;
private Type[] genericMethodArguments;
+ protected readonly object proxyObject;
protected object target;
protected AbstractInvocation(
@@ -48,7 +48,7 @@
Debug.Assert(proxiedMethod != null);
this.target = target;
this.targetType = targetType;
- this.proxy = proxy;
+ this.proxyObject = proxy;
this.interceptors = interceptors;
this.proxiedMethod = proxiedMethod;
this.arguments = arguments;
@@ -82,7 +82,7 @@
throw new NotImplementedException(message);
}
- if (!ReferenceEquals(target, proxy))
+ if (!ReferenceEquals(target, proxyObject))
{
return;
}
@@ -92,11 +92,27 @@
throw new InvalidOperationException(message);
}
+ protected void EnsureValidProxyTarget(object target)
+ {
+ if (target == null)
+ {
+ throw new ArgumentNullException("target");
+ }
+
+ if (!ReferenceEquals(target, proxyObject))
+ {
+ return;
+ }
+ var message = "This is a DynamicProxy2 error: target of
proxy has been set to the proxy itself. " +
+ "This would result in recursively calling
proxy methods over and over again until stack overflow, which may destabilize
your program." +
+ "This usually signifies a bug in the
calling code. Make sure no interceptor sets proxy as its own target.";
+ throw new InvalidOperationException(message);
+ }
+
private IInterceptor[]
SelectMethodInterceptors(IInterceptorSelector selector, IInterceptor[]
methodInterceptors)
{
if (methodInterceptors == null)
{
- //NOTE: perhaps instead of passing this.Method
we should call this.GetConcreteMethod()
methodInterceptors =
selector.SelectInterceptors(TargetType, Method, interceptors) ??
new IInterceptor[0];
}
@@ -115,7 +131,7 @@
public object Proxy
{
- get { return proxy; }
+ get { return proxyObject; }
}
--
You received this message because you are subscribed to the Google Groups
"Castle Project Commits" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/castle-project-commits?hl=.