User: xtoff
Date: 2009/11/15 08:48 AM
Added:
/DynamicProxy/trunk/src/Castle.DynamicProxy.Tests/
InvocationTypesCachingTestCase.cs
Modified:
/DynamicProxy/trunk/src/Castle.DynamicProxy.Tests/
Castle.DynamicProxy.Tests-vs2008.csproj
/DynamicProxy/trunk/src/Castle.DynamicProxy/Contributors/
InterfaceProxyTargetContributor.cs,
InterfaceProxyWithoutTargetContributor.cs, MixinContributor.cs
/DynamicProxy/trunk/src/Castle.DynamicProxy/Generators/
CacheKey.cs, INamingScope.cs, InterfaceInvocationTypeGenerator.cs,
InvocationTypeGenerator.cs, NamingScope.cs
/DynamicProxy/trunk/src/Castle.DynamicProxy/Generators/Emitters/
ClassEmitter.cs
Log:
- Fixed DYNPROXY-ISSUE-105 - Invocation types should be cached and shared
among proxy implementations.
File Changes:
Directory: /DynamicProxy/trunk/src/Castle.DynamicProxy.Tests/
=============================================================
File [modified]: Castle.DynamicProxy.Tests-vs2008.csproj
Delta lines: +60 -0
===================================================================
---
DynamicProxy/trunk/src/Castle.DynamicProxy.Tests/InvocationTypesCachingTestCase.cs
(rev 0)
+++
DynamicProxy/trunk/src/Castle.DynamicProxy.Tests/InvocationTypesCachingTestCase.cs
2009-11-15 15:48:03 UTC (rev 6332)
@@ -0,0 +1,60 @@
+// Copyright 2004-2009 Castle Project - http://www.castleproject.org/
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+namespace Castle.DynamicProxy.Tests
+{
+ using Castle.Core.Interceptor;
+ using Castle.DynamicProxy.Tests.Interceptors;
+ using Castle.DynamicProxy.Tests.Interfaces;
+
+ using NUnit.Framework;
+
+ [TestFixture]
+ public class InvocationTypesCachingTestCase:BasePEVerifyTestCase
+ {
+ [Test]
+ public void Should_share_invocations_for_interface_methods()
+ {
+ var interceptor1 = new KeepDataInterceptor();
+ var interceptor2 = new KeepDataInterceptor();
+ var first =
generator.CreateInterfaceProxyWithTarget<IOne>(new One(), interceptor1);
+ var second =
generator.CreateInterfaceProxyWithTarget<IOne>(new OneTwo(), interceptor2);
+
+ Assert.AreNotEqual(first.GetType(), second.GetType(),
"proxy types are different");
+
+ first.OneMethod();
+ second.OneMethod();
+
+ Assert.AreEqual(interceptor1.Invocation.GetType(),
interceptor2.Invocation.GetType());
+ }
+
+ [Test]
+ public void
Should_not_share_invocations_for_interface_methods_when_one_is_IChangeProxyTarget()
+ {
+ var interceptor1 = new KeepDataInterceptor();
+ var interceptor2 = new KeepDataInterceptor();
+ var first =
generator.CreateInterfaceProxyWithTarget<IOne>(new One(), interceptor1);
+ var second =
generator.CreateInterfaceProxyWithTargetInterface<IOne>(new OneTwo(),
interceptor2);
+
+ Assert.AreNotEqual(first.GetType(), second.GetType(),
"proxy types are different");
+
+ first.OneMethod();
+ second.OneMethod();
+
+
Assert.IsNotInstanceOf<IChangeProxyTarget>(interceptor1.Invocation);
+
Assert.IsInstanceOf<IChangeProxyTarget>(interceptor2.Invocation);
+ Assert.AreNotEqual(interceptor1.Invocation.GetType(),
interceptor2.Invocation.GetType());
+ }
+ }
+}
File [added]: InvocationTypesCachingTestCase.cs
Delta lines: +0 -0
===================================================================
Directory: /DynamicProxy/trunk/src/Castle.DynamicProxy/Contributors/
====================================================================
File [modified]: InterfaceProxyTargetContributor.cs
Delta lines: +30 -10
===================================================================
---
DynamicProxy/trunk/src/Castle.DynamicProxy/Contributors/InterfaceProxyWithoutTargetContributor.cs
2009-11-15 12:24:41 UTC (rev 6331)
+++
DynamicProxy/trunk/src/Castle.DynamicProxy/Contributors/InterfaceProxyWithoutTargetContributor.cs
2009-11-15 15:48:03 UTC (rev 6332)
@@ -103,21 +103,17 @@
MethodGenerator generator;
if (method.Proxyable)
{
- var invocation = new
InterfaceInvocationTypeGenerator(method.Method.DeclaringType,
-
method,
-
method.MethodOnTarget,
-
false)
- .Generate(@class, options,
namingScope).BuildType();
+ var invocation = GetInvocationType(method,
@class, options);
generator = new InterfaceMethodGenerator(method,
-
invocation,
-
@class.GetField("__interceptors"),
-
createMethod,
-
getTargetExpressionDelegate);
+
invocation,
+
@class.GetField("__interceptors"),
+
createMethod,
+
getTargetExpressionDelegate);
}
else
{
- generator= new
MinimialisticMethodGenerator(method, createMethod,
GeneratorUtil.ObtainInterfaceMethodAttributes);
+ generator = new
MinimialisticMethodGenerator(method, createMethod,
GeneratorUtil.ObtainInterfaceMethodAttributes);
}
var proxiedMethod = generator.Generate(@class, options,
namingScope);
@@ -126,5 +122,29 @@
proxiedMethod.DefineCustomAttribute(attribute);
}
}
+
+ private Type GetInvocationType(MethodToGenerate method,
ClassEmitter emitter, ProxyGenerationOptions options)
+ {
+ var scope = emitter.ModuleScope;
+ var key = new CacheKey(method.Method, null, null);
+
+ // no locking required as we're already within a lock
+
+ var invocation = scope.GetFromCache(key);
+ if (invocation != null)
+ {
+ return invocation;
+ }
+
+ invocation = new
InterfaceInvocationTypeGenerator(method.Method.DeclaringType,
+
method,
+
method.Method,
+
false)
+ .Generate(emitter, options,
namingScope).BuildType();
+
+ scope.RegisterInCache(key, invocation);
+
+ return invocation;
+ }
}
}
File [modified]: InterfaceProxyWithoutTargetContributor.cs
Delta lines: +31 -5
===================================================================
--- DynamicProxy/trunk/src/Castle.DynamicProxy/Contributors/MixinContributor.cs
2009-11-15 12:24:41 UTC (rev 6331)
+++ DynamicProxy/trunk/src/Castle.DynamicProxy/Contributors/MixinContributor.cs
2009-11-15 15:48:03 UTC (rev 6332)
@@ -17,6 +17,7 @@
using System;
using System.Diagnostics;
+ using Castle.Core.Interceptor;
using Castle.DynamicProxy.Generators;
using Castle.DynamicProxy.Generators.Emitters;
@@ -116,11 +117,7 @@
MethodGenerator generator;
if (method.Proxyable)
{
- var invocation = new
InterfaceInvocationTypeGenerator(method.Method.DeclaringType,
-
method,
-
method.Method,
-
canChangeTarget)
- .Generate(emitter, options,
namingScope).BuildType();
+ var invocation = GetInvocationType(method,
emitter, options);
var interceptors =
emitter.GetField("__interceptors");
@@ -143,6 +140,35 @@
}
}
+ private Type GetInvocationType(MethodToGenerate method,
ClassEmitter emitter, ProxyGenerationOptions options)
+ {
+ var scope = emitter.ModuleScope;
+ Type[] interfaces = Type.EmptyTypes;
+ if (canChangeTarget)
+ {
+ interfaces = new[] { typeof(IChangeProxyTarget)
};
+ }
+ var key = new CacheKey(method.Method, interfaces, null);
+
+ // no locking required as we're already within a lock
+
+ var invocation = scope.GetFromCache(key);
+ if(invocation!=null)
+ {
+ return invocation;
+ }
+
+ invocation = new
InterfaceInvocationTypeGenerator(method.Method.DeclaringType,
+
method,
+
method.Method,
+
canChangeTarget)
+ .Generate(emitter, options,
namingScope).BuildType();
+
+ scope.RegisterInCache(key, invocation);
+
+ return invocation;
+ }
+
public void SetGetTargetExpression(GetTargetExpressionDelegate
getTarget)
{
File [modified]: MixinContributor.cs
Delta lines: +11 -12
===================================================================
--- DynamicProxy/trunk/src/Castle.DynamicProxy/Generators/CacheKey.cs
2009-11-15 12:24:41 UTC (rev 6331)
+++ DynamicProxy/trunk/src/Castle.DynamicProxy/Generators/CacheKey.cs
2009-11-15 15:48:03 UTC (rev 6332)
@@ -15,6 +15,7 @@
namespace Castle.DynamicProxy.Generators
{
using System;
+ using System.Reflection;
#if SILVERLIGHT
#else
@@ -22,7 +23,7 @@
#endif
public class CacheKey
{
- private readonly Type targetType;
+ private readonly MemberInfo target;
private readonly Type[] interfaces;
private readonly ProxyGenerationOptions options;
private readonly Type proxyForType;
@@ -30,12 +31,12 @@
/// <summary>
/// Initializes a new instance of the <see cref="CacheKey"/>
class.
/// </summary>
- /// <param name="targetType">Type of the target.</param>
+ /// <param name="target">Type of the target.</param>
/// <param name="interfaces">The interfaces.</param>
/// <param name="options">The options.</param>
- public CacheKey(Type targetType, Type[] interfaces,
ProxyGenerationOptions options)
+ public CacheKey(MemberInfo target, Type[] interfaces,
ProxyGenerationOptions options)
{
- this.targetType = targetType;
+ this.target = target;
this.interfaces = interfaces ?? Type.EmptyTypes;
this.options = options;
}
@@ -48,15 +49,13 @@
public override int GetHashCode()
{
- int result = targetType.GetHashCode();
- if (interfaces != null)
+ int result = target.GetHashCode();
+ foreach (Type inter in interfaces)
{
- foreach (Type inter in interfaces)
- {
- result += 29 + inter.GetHashCode();
- }
+ result += 29 + inter.GetHashCode();
}
- result = 29*result + options.GetHashCode();
+ if (options != null)
+ result = 29*result + options.GetHashCode();
if (proxyForType != null)
result = 29*result + proxyForType.GetHashCode();
return result;
@@ -70,7 +69,7 @@
if (cacheKey == null) return false;
if (!Equals(proxyForType, cacheKey.proxyForType))
return false;
- if (!Equals(targetType, cacheKey.targetType)) return
false;
+ if (!Equals(target, cacheKey.target)) return false;
if (interfaces.Length != cacheKey.interfaces.Length)
return false;
for (int i = 0; i < interfaces.Length; i++)
Directory: /DynamicProxy/trunk/src/Castle.DynamicProxy/Generators/Emitters/
===========================================================================
File [modified]: ClassEmitter.cs
Delta lines: +2 -0
===================================================================
--- DynamicProxy/trunk/src/Castle.DynamicProxy/Generators/INamingScope.cs
2009-11-15 12:24:41 UTC (rev 6331)
+++ DynamicProxy/trunk/src/Castle.DynamicProxy/Generators/INamingScope.cs
2009-11-15 15:48:03 UTC (rev 6332)
@@ -39,5 +39,7 @@
/// </summary>
/// <returns>New naming scope.</returns>
INamingScope SafeSubScope();
+
+ INamingScope ParentScope { get; }
}
}
Directory: /DynamicProxy/trunk/src/Castle.DynamicProxy/Generators/
==================================================================
File [modified]: CacheKey.cs
Delta lines: +1 -1
===================================================================
---
DynamicProxy/trunk/src/Castle.DynamicProxy/Generators/Emitters/ClassEmitter.cs
2009-11-15 12:24:41 UTC (rev 6331)
+++
DynamicProxy/trunk/src/Castle.DynamicProxy/Generators/Emitters/ClassEmitter.cs
2009-11-15 15:48:03 UTC (rev 6332)
@@ -21,7 +21,7 @@
public class ClassEmitter : AbstractTypeEmitter
{
- private ModuleScope moduleScope;
+ private readonly ModuleScope moduleScope;
private const TypeAttributes DefaultAttributes =
TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Serializable;
File [modified]: INamingScope.cs
Delta lines: +4 -5
===================================================================
---
DynamicProxy/trunk/src/Castle.DynamicProxy/Generators/InterfaceInvocationTypeGenerator.cs
2009-11-15 12:24:41 UTC (rev 6331)
+++
DynamicProxy/trunk/src/Castle.DynamicProxy/Generators/InterfaceInvocationTypeGenerator.cs
2009-11-15 15:48:03 UTC (rev 6332)
@@ -29,11 +29,10 @@
protected override AbstractTypeEmitter GetEmitter(ClassEmitter
@class, Type[] interfaces, INamingScope namingScope, MethodInfo methodInfo)
{
- return new ClassEmitter(@class.ModuleScope,
- namingScope.GetUniqueName(
-
string.Format("Castle.Invocations.{0}_{1}", methodInfo.DeclaringType.Name,
methodInfo.Name)),
- typeof(AbstractInvocation),
interfaces);
-
+ var suggestedName =
string.Format("Castle.Proxies.Invocations.{0}_{1}",
methodInfo.DeclaringType.Name,
+ methodInfo.Name);
+ var uniqueName =
namingScope.ParentScope.GetUniqueName(suggestedName);
+ return new ClassEmitter(@class.ModuleScope, uniqueName,
typeof(AbstractInvocation), interfaces);
}
File [modified]: InterfaceInvocationTypeGenerator.cs
Delta lines: +3 -3
===================================================================
---
DynamicProxy/trunk/src/Castle.DynamicProxy/Generators/InvocationTypeGenerator.cs
2009-11-15 12:24:41 UTC (rev 6331)
+++
DynamicProxy/trunk/src/Castle.DynamicProxy/Generators/InvocationTypeGenerator.cs
2009-11-15 15:48:03 UTC (rev 6332)
@@ -89,9 +89,9 @@
protected virtual AbstractTypeEmitter GetEmitter(ClassEmitter
@class, Type[] interfaces, INamingScope namingScope, MethodInfo methodInfo)
{
return new NestedClassEmitter(@class,
-
namingScope.GetUniqueName("Invocation_" + methodInfo.Name),
-
typeof(AbstractInvocation),
- interfaces);
+
namingScope.GetUniqueName("Invocation_" + methodInfo.Name),
+
typeof(AbstractInvocation),
+
interfaces);
}
File [modified]: InvocationTypeGenerator.cs
Delta lines: +16 -1
===================================================================
--- DynamicProxy/trunk/src/Castle.DynamicProxy/Generators/NamingScope.cs
2009-11-15 12:24:41 UTC (rev 6331)
+++ DynamicProxy/trunk/src/Castle.DynamicProxy/Generators/NamingScope.cs
2009-11-15 15:48:03 UTC (rev 6332)
@@ -20,7 +20,17 @@
public class NamingScope : INamingScope
{
private readonly IDictionary<string,int> names = new
Dictionary<string, int>();
+ private readonly INamingScope parentScope;
+ public NamingScope()
+ {
+ }
+
+ private NamingScope(INamingScope parent)
+ {
+ parentScope = parent;
+ }
+
public string GetUniqueName(string suggestedName)
{
Debug.Assert(string.IsNullOrEmpty(suggestedName) ==
false,
@@ -40,7 +50,12 @@
public INamingScope SafeSubScope()
{
- return new NamingScope();
+ return new NamingScope(this);
}
+
+ public INamingScope ParentScope
+ {
+ get { return parentScope;}
+ }
}
}
File [modified]: NamingScope.cs
Delta lines: +1 -0
===================================================================
---
DynamicProxy/trunk/src/Castle.DynamicProxy.Tests/Castle.DynamicProxy.Tests-vs2008.csproj
2009-11-15 12:24:41 UTC (rev 6331)
+++
DynamicProxy/trunk/src/Castle.DynamicProxy.Tests/Castle.DynamicProxy.Tests-vs2008.csproj
2009-11-15 15:48:03 UTC (rev 6332)
@@ -185,6 +185,7 @@
<Compile Include="Interfaces\OneTwo.cs" />
<Compile Include="Interfaces\Two.cs" />
<Compile Include="InvocationMethodInvocationTargetTestCase.cs" />
+ <Compile Include="InvocationTypesCachingTestCase.cs" />
<Compile Include="MethodEquivalenceTestCase.cs" />
<Compile Include="MixinDataTestCase.cs" />
--
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=.