svn commit: rev 43424 - in avalon/trunk/central/laboratory/avalon-net/DynamicProxy: . Builder Builder/CodeGenerators DynamicProxyTest DynamicProxyTest/ClassInterfaces DynamicProxyTest/Classes
[email protected] 6 Sep 2004 20:43:17 -0000
| Newsgroups | gmane.comp.jakarta.avalon.cvs |
|---|---|
| Message-ID | <[email protected]> |
Author: hammett
Date: Mon Sep 6 13:43:16 2004
New Revision: 43424
Added:
avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/
avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/CodeGenerators/
avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/CodeGenerators/BaseCodeGenerator.cs (contents, props changed)
avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/CodeGenerators/ClassProxyGenerator.cs (contents, props changed)
avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/CodeGenerators/InterfaceProxyGenerator.cs (contents, props changed)
avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/CodeGenerators/OpCodesDictionary.cs (contents, props changed)
avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/IProxyBuilder.cs (contents, props changed)
avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/ProxyBuilderImpl.cs (contents, props changed)
avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/ClassInterfaces/
avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/ClassInterfaces/IMyInterface.cs (contents, props changed)
avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/ClassInterfaces/IMySecondInterface.cs (contents, props changed)
avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/ClassInterfaces/IServiceStatus.cs (contents, props changed)
avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/ClassInterfaces/MyInterfaceImpl.cs (contents, props changed)
avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/ClassInterfaces/MySecondInterfaceImpl.cs (contents, props changed)
avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/ClassInterfaces/ServiceStatusImpl.cs (contents, props changed)
avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/Classes/
avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/Classes/NoVirtualMethodClass.cs (contents, props changed)
avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/Classes/SealedMethodsClass.cs (contents, props changed)
avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/Classes/ServiceClass.cs (contents, props changed)
avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/Classes/SpecializedServiceClass.cs (contents, props changed)
Removed:
avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/IMyInterface.cs
avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/IMySecondInterface.cs
avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/IServiceStatus.cs
avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/MyInterfaceImpl.cs
avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/MySecondInterfaceImpl.cs
avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/ServiceStatusImpl.cs
Modified:
avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Apache.Avalon.DynamicProxy.csproj
avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/Apache.Avalon.DynamicProxy.Test.csproj
avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/ProxyGeneratorTestCase.cs
avalon/trunk/central/laboratory/avalon-net/DynamicProxy/ProxyGenerator.cs
Log:
Supports proxying classes and interfaces now.
Modified: avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Apache.Avalon.DynamicProxy.csproj
==============================================================================
--- avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Apache.Avalon.DynamicProxy.csproj (original)
+++ avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Apache.Avalon.DynamicProxy.csproj Mon Sep 6 13:43:16 2004
@@ -103,6 +103,36 @@
SubType = "Code"
BuildAction = "Compile"
/>
+ <File
+ RelPath = "Builder\IProxyBuilder.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "Builder\ProxyBuilderImpl.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "Builder\CodeGenerators\BaseCodeGenerator.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "Builder\CodeGenerators\ClassProxyGenerator.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "Builder\CodeGenerators\InterfaceProxyGenerator.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "Builder\CodeGenerators\OpCodesDictionary.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
</Include>
</Files>
</CSHARP>
Added: avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/CodeGenerators/BaseCodeGenerator.cs
==============================================================================
--- (empty file)
+++ avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/CodeGenerators/BaseCodeGenerator.cs Mon Sep 6 13:43:16 2004
@@ -0,0 +1,372 @@
+ // Copyright 2004 The Apache Software Foundation
+//
+// 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 Apache.Avalon.DynamicProxy.Builder.CodeGenerators
+{
+ using System;
+ using System.Collections;
+ using System.Reflection;
+ using System.Reflection.Emit;
+
+ /// <summary>
+ /// Summary description for BaseCodeGenerator.
+ /// </summary>
+ public abstract class BaseCodeGenerator
+ {
+ private TypeBuilder m_typeBuilder;
+ private FieldBuilder m_handlerField;
+ private IList m_generated = new ArrayList();
+
+ protected TypeBuilder MainTypeBuilder
+ {
+ get { return m_typeBuilder; }
+ }
+
+ protected FieldBuilder HandlerFieldBuilder
+ {
+ get { return m_handlerField; }
+ }
+
+ protected virtual ModuleBuilder CreateDynamicModule()
+ {
+ AssemblyName assemblyName = new AssemblyName();
+ assemblyName.Name = "DynamicAssemblyProxyGen";
+
+ AssemblyBuilder assemblyBuilder =
+ AppDomain.CurrentDomain.DefineDynamicAssembly(
+ assemblyName,
+ AssemblyBuilderAccess.Run);
+
+ return assemblyBuilder.DefineDynamicModule(assemblyName.Name, true);
+ }
+
+ protected virtual TypeBuilder CreateTypeBuilder(Type baseType, Type[] interfaces)
+ {
+ ModuleBuilder moduleBuilder = CreateDynamicModule();
+
+ m_typeBuilder = moduleBuilder.DefineType(
+ "ProxyType", TypeAttributes.Public | TypeAttributes.Class, baseType, interfaces);
+
+ m_handlerField = GenerateField();
+ ConstructorBuilder constr = GenerateConstructor();
+
+ return m_typeBuilder;
+ }
+
+ /// <summary>
+ /// Generates a public field holding the <see cref="IInvocationHandler"/>
+ /// </summary>
+ /// <returns><see cref="FieldBuilder"/> instance</returns>
+ protected FieldBuilder GenerateField()
+ {
+ return m_typeBuilder.DefineField("handler",
+ typeof (IInvocationHandler), FieldAttributes.Public);
+ }
+
+ /// <summary>
+ /// Generates one public constructor receiving
+ /// the <see cref="IInvocationHandler"/> instance.
+ /// </summary>
+ /// <returns><see cref="ConstructorBuilder"/> instance</returns>
+ protected ConstructorBuilder GenerateConstructor()
+ {
+ ConstructorBuilder consBuilder = m_typeBuilder.DefineConstructor(
+ MethodAttributes.Public,
+ CallingConventions.Standard,
+ new Type[] {typeof (IInvocationHandler)});
+
+ ILGenerator ilGenerator = consBuilder.GetILGenerator();
+ ilGenerator.Emit(OpCodes.Ldarg_0);
+ ilGenerator.Emit(OpCodes.Call, typeof (Object).GetConstructor(new Type[0]));
+ ilGenerator.Emit(OpCodes.Ldarg_0);
+ ilGenerator.Emit(OpCodes.Ldarg_1);
+ ilGenerator.Emit(OpCodes.Stfld, m_handlerField);
+ ilGenerator.Emit(OpCodes.Ret);
+
+ return consBuilder;
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="interfaces"></param>
+ protected void GenerateInterfaceImplementation(Type[] interfaces)
+ {
+ foreach(Type inter in interfaces)
+ {
+ GenerateTypeImplementation(inter);
+ }
+ }
+
+ /// <summary>
+ /// Iterates over the interfaces and generate implementation
+ /// for each method in it.
+ /// </summary>
+ /// <param name="type">Interface type</param>
+ protected void GenerateTypeImplementation(Type type)
+ {
+ if (m_generated.Contains(type))
+ {
+ return;
+ }
+ else
+ {
+ m_generated.Add( type );
+ }
+
+ Type[] baseInterfaces = type.FindInterfaces(new TypeFilter(NoFilterImpl), type);
+
+ GenerateInterfaceImplementation(baseInterfaces);
+ PropertyBuilder[] propertiesBuilder = GenerateProperties(type);
+ GenerateMethods(type, propertiesBuilder);
+ }
+
+ protected virtual PropertyBuilder[] GenerateProperties( Type inter )
+ {
+ PropertyInfo[] properties = inter.GetProperties();
+ PropertyBuilder[] propertiesBuilder = new PropertyBuilder[properties.Length];
+
+ for(int i = 0; i < properties.Length; i++)
+ {
+ propertiesBuilder[i] = GeneratePropertyImplementation(properties[i]);
+ }
+
+ return propertiesBuilder;
+ }
+
+ protected virtual void GenerateMethods( Type inter, PropertyBuilder[] propertiesBuilder )
+ {
+ MethodInfo[] methods = inter.GetMethods();
+
+ foreach(MethodInfo method in methods)
+ {
+ GenerateMethodImplementation(method, propertiesBuilder);
+ }
+ }
+
+ /// <summary>
+ /// Generate property implementation
+ /// </summary>
+ /// <param name="property"></param>
+ protected PropertyBuilder GeneratePropertyImplementation(PropertyInfo property)
+ {
+ return m_typeBuilder.DefineProperty(
+ property.Name, property.Attributes, property.PropertyType, null);
+ }
+
+ /// <summary>
+ /// Generates implementation for each method.
+ /// </summary>
+ /// <param name="method"></param>
+ /// <param name="properties"></param>
+ protected void GenerateMethodImplementation(
+ MethodInfo method, PropertyBuilder[] properties)
+ {
+ if (method.IsFinal)
+ {
+ return;
+ }
+
+ ParameterInfo[] parameterInfo = method.GetParameters();
+
+ Type[] parameters = new Type[parameterInfo.Length];
+
+ for(int i = 0; i < parameterInfo.Length; i++)
+ {
+ parameters[i] = parameterInfo[i].ParameterType;
+ }
+
+ MethodAttributes atts = MethodAttributes.Public | MethodAttributes.Virtual;
+
+ if (method.Name.StartsWith("set_") || method.Name.StartsWith("get_"))
+ {
+ atts = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Virtual;
+ }
+
+ MethodBuilder methodBuilder =
+ m_typeBuilder.DefineMethod(method.Name, atts, CallingConventions.Standard,
+ method.ReturnType, parameters);
+
+ if (method.Name.StartsWith("set_") || method.Name.StartsWith("get_"))
+ {
+ foreach(PropertyBuilder property in properties)
+ {
+ if (property == null)
+ {
+ break;
+ }
+
+ if (!property.Name.Equals(method.Name.Substring(4)))
+ {
+ continue;
+ }
+
+ if (methodBuilder.Name.StartsWith("set_"))
+ {
+ property.SetSetMethod(methodBuilder);
+ break;
+ }
+ else
+ {
+ property.SetGetMethod(methodBuilder);
+ break;
+ }
+ }
+ }
+
+ WriteILForMethod(method, methodBuilder, parameters, HandlerFieldBuilder);
+ }
+
+ /// <summary>
+ /// Writes the stack for the method implementation. This
+ /// method generates the IL stack for property get/set method and
+ /// ordinary methods.
+ /// </summary>
+ /// <remarks>
+ /// The method implementation would be as simple as:
+ /// <code>
+ /// public void SomeMethod( int parameter )
+ /// {
+ /// MethodBase method = MethodBase.GetCurrentMethod();
+ /// handler.Invoke( this, method, new object[] { parameter } );
+ /// }
+ /// </code>
+ /// </remarks>
+ /// <param name="builder"><see cref="MethodBuilder"/> being constructed.</param>
+ /// <param name="parameters"></param>
+ /// <param name="handlerField"></param>
+ protected void WriteILForMethod(MethodInfo method, MethodBuilder builder,
+ Type[] parameters, FieldBuilder handlerField)
+ {
+ int arrayPositionInStack = 1;
+
+ ILGenerator ilGenerator = builder.GetILGenerator();
+
+ ilGenerator.DeclareLocal(typeof (MethodBase));
+
+ if (builder.ReturnType != typeof (void))
+ {
+ ilGenerator.DeclareLocal(builder.ReturnType);
+ arrayPositionInStack = 2;
+ }
+
+ ilGenerator.DeclareLocal(typeof (object[]));
+
+ ilGenerator.Emit(OpCodes.Ldtoken, method);
+ ilGenerator.Emit(OpCodes.Call, typeof (MethodBase).GetMethod("GetMethodFromHandle"));
+
+ ilGenerator.Emit(OpCodes.Stloc_0);
+ ilGenerator.Emit(OpCodes.Ldarg_0);
+ ilGenerator.Emit(OpCodes.Ldfld, handlerField);
+ ilGenerator.Emit(OpCodes.Ldarg_0);
+ ilGenerator.Emit(OpCodes.Ldloc_0);
+ ilGenerator.Emit(OpCodes.Ldc_I4, parameters.Length);
+ ilGenerator.Emit(OpCodes.Newarr, typeof (object));
+
+ if (parameters.Length != 0)
+ {
+ ilGenerator.Emit(OpCodes.Stloc, arrayPositionInStack);
+ ilGenerator.Emit(OpCodes.Ldloc, arrayPositionInStack);
+ }
+
+ for(int c = 0; c < parameters.Length; c++)
+ {
+ ilGenerator.Emit(OpCodes.Ldc_I4, c);
+ ilGenerator.Emit(OpCodes.Ldarg, c + 1);
+
+ if (parameters[c].IsValueType)
+ {
+ ilGenerator.Emit(OpCodes.Box, parameters[c].UnderlyingSystemType);
+ }
+
+ ilGenerator.Emit(OpCodes.Stelem_Ref);
+ ilGenerator.Emit(OpCodes.Ldloc, arrayPositionInStack);
+ }
+
+ ilGenerator.Emit(OpCodes.Callvirt, typeof (IInvocationHandler).GetMethod("Invoke"));
+
+ if (builder.ReturnType != typeof (void))
+ {
+ if (!builder.ReturnType.IsValueType)
+ {
+ ilGenerator.Emit(OpCodes.Castclass, builder.ReturnType);
+ }
+ else
+ {
+ ilGenerator.Emit(OpCodes.Unbox, builder.ReturnType);
+ ilGenerator.Emit(ConvertTypeToOpCode(builder.ReturnType));
+ }
+
+ ilGenerator.Emit(OpCodes.Stloc, 1);
+
+ Label label = ilGenerator.DefineLabel();
+ ilGenerator.Emit(OpCodes.Br_S, label);
+ ilGenerator.MarkLabel(label);
+ ilGenerator.Emit(OpCodes.Ldloc, 1);
+ }
+ else
+ {
+ ilGenerator.Emit(OpCodes.Pop);
+ }
+
+ ilGenerator.Emit(OpCodes.Ret);
+ }
+
+ /// <summary>
+ /// Converts a Value type to a correspondent OpCode of
+ /// </summary>
+ /// <param name="type"></param>
+ /// <returns></returns>
+ protected virtual OpCode ConvertTypeToOpCode(Type type)
+ {
+ if (type.IsEnum)
+ {
+ Enum baseType = (Enum) Activator.CreateInstance(type);
+ TypeCode code = baseType.GetTypeCode();
+
+ switch(code)
+ {
+ case TypeCode.Byte:
+ type = typeof (Byte);
+ break;
+ case TypeCode.Int16:
+ type = typeof (Int16);
+ break;
+ case TypeCode.Int32:
+ type = typeof (Int32);
+ break;
+ case TypeCode.Int64:
+ type = typeof (Int64);
+ break;
+ }
+
+ return ConvertTypeToOpCode(type);
+ }
+
+ OpCode opCode = OpCodesDictionary.Instance[ type ];
+
+ if (Object.ReferenceEquals(opCode, OpCodesDictionary.EmptyOpCode))
+ {
+ throw new ArgumentException("Type " + type + " could not be converted to a OpCode");
+ }
+
+ return opCode;
+ }
+
+ public static bool NoFilterImpl(Type type, object criteria)
+ {
+ return true;
+ }
+ }
+}
\ No newline at end of file
Added: avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/CodeGenerators/ClassProxyGenerator.cs
==============================================================================
--- (empty file)
+++ avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/CodeGenerators/ClassProxyGenerator.cs Mon Sep 6 13:43:16 2004
@@ -0,0 +1,34 @@
+// Copyright 2004 The Apache Software Foundation
+//
+// 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 Apache.Avalon.DynamicProxy.Builder.CodeGenerators
+{
+ using System;
+
+ /// <summary>
+ /// Summary description for ClassProxyGenerator.
+ /// </summary>
+ public class ClassProxyGenerator : BaseCodeGenerator
+ {
+ public Type GenerateCode(Type baseClass)
+ {
+ // TODO: interfaces of base class
+
+ CreateTypeBuilder( baseClass, new Type[0] );
+ GenerateTypeImplementation( baseClass );
+
+ return MainTypeBuilder.CreateType();
+ }
+ }
+}
Added: avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/CodeGenerators/InterfaceProxyGenerator.cs
==============================================================================
--- (empty file)
+++ avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/CodeGenerators/InterfaceProxyGenerator.cs Mon Sep 6 13:43:16 2004
@@ -0,0 +1,37 @@
+ // Copyright 2004 The Apache Software Foundation
+//
+// 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 Apache.Avalon.DynamicProxy.Builder.CodeGenerators
+{
+ using System;
+ using System.Reflection;
+ using System.Reflection.Emit;
+
+ /// <summary>
+ /// Summary description for InterfaceProxyGenerator.
+ /// </summary>
+ public class InterfaceProxyGenerator : BaseCodeGenerator
+ {
+ public InterfaceProxyGenerator()
+ {
+ }
+
+ public Type GenerateCode(Type[] interfaces)
+ {
+ CreateTypeBuilder( null, interfaces );
+ GenerateInterfaceImplementation( interfaces );
+ return MainTypeBuilder.CreateType();
+ }
+ }
+}
\ No newline at end of file
Added: avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/CodeGenerators/OpCodesDictionary.cs
==============================================================================
--- (empty file)
+++ avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/CodeGenerators/OpCodesDictionary.cs Mon Sep 6 13:43:16 2004
@@ -0,0 +1,64 @@
+using System.Reflection.Emit;
+// Copyright 2004 The Apache Software Foundation
+//
+// 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 Apache.Avalon.DynamicProxy.Builder.CodeGenerators
+{
+ using System;
+ using System.Collections;
+
+ /// <summary>
+ /// Summary description for OpCodesDictionary.
+ /// </summary>
+ public sealed class OpCodesDictionary : DictionaryBase
+ {
+ private static readonly OpCodesDictionary m_dict = new OpCodesDictionary();
+
+ private static readonly OpCode m_emptyOpCode = new OpCode();
+
+ private OpCodesDictionary() : base()
+ {
+ Dictionary[ typeof (Int16) ] = OpCodes.Ldind_I2;
+ Dictionary[ typeof (Int32) ] = OpCodes.Ldind_I4;
+ Dictionary[ typeof (Int64) ] = OpCodes.Ldind_I8;
+ Dictionary[ typeof (float) ] = OpCodes.Ldind_R4;
+ Dictionary[ typeof (double) ] = OpCodes.Ldind_R8;
+ Dictionary[ typeof (UInt16) ] = OpCodes.Ldind_U2;
+ Dictionary[ typeof (UInt32) ] = OpCodes.Ldind_U4;
+ Dictionary[ typeof (bool) ] = OpCodes.Ldind_I4;
+ }
+
+ public OpCode this[Type type]
+ {
+ get
+ {
+ if (Dictionary.Contains(type))
+ {
+ return (OpCode) Dictionary[ type ];
+ }
+ return EmptyOpCode;
+ }
+ }
+
+ public static OpCodesDictionary Instance
+ {
+ get { return m_dict; }
+ }
+
+ public static OpCode EmptyOpCode
+ {
+ get { return m_emptyOpCode; }
+ }
+ }
+}
\ No newline at end of file
Added: avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/IProxyBuilder.cs
==============================================================================
--- (empty file)
+++ avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/IProxyBuilder.cs Mon Sep 6 13:43:16 2004
@@ -0,0 +1,28 @@
+// Copyright 2004 The Apache Software Foundation
+//
+// 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 Apache.Avalon.DynamicProxy.Builder
+{
+ using System;
+
+ /// <summary>
+ /// Summary description for IProxyBuilder.
+ /// </summary>
+ public interface IProxyBuilder
+ {
+ Type CreateInterfaceProxy( Type[] interfaces );
+
+ Type CreateClassProxy( Type theClass );
+ }
+}
Added: avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/ProxyBuilderImpl.cs
==============================================================================
--- (empty file)
+++ avalon/trunk/central/laboratory/avalon-net/DynamicProxy/Builder/ProxyBuilderImpl.cs Mon Sep 6 13:43:16 2004
@@ -0,0 +1,41 @@
+using Apache.Avalon.DynamicProxy.Builder.CodeGenerators;
+// Copyright 2004 The Apache Software Foundation
+//
+// 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 Apache.Avalon.DynamicProxy.Builder
+{
+ using System;
+
+ /// <summary>
+ /// Summary description for ProxyBuilderImpl.
+ /// </summary>
+ public class ProxyBuilderImpl : IProxyBuilder
+ {
+ #region IProxyBuilder Members
+
+ public Type CreateInterfaceProxy(Type[] interfaces)
+ {
+ InterfaceProxyGenerator generator = new InterfaceProxyGenerator();
+ return generator.GenerateCode( interfaces );
+ }
+
+ public Type CreateClassProxy(Type theClass)
+ {
+ ClassProxyGenerator generator = new ClassProxyGenerator();
+ return generator.GenerateCode( theClass );
+ }
+
+ #endregion
+ }
+}
Modified: avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/Apache.Avalon.DynamicProxy.Test.csproj
==============================================================================
--- avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/Apache.Avalon.DynamicProxy.Test.csproj (original)
+++ avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/Apache.Avalon.DynamicProxy.Test.csproj Mon Sep 6 13:43:16 2004
@@ -99,37 +99,57 @@
BuildAction = "Compile"
/>
<File
- RelPath = "IMyInterface.cs"
+ RelPath = "ProxyGeneratorTestCase.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
- RelPath = "IMySecondInterface.cs"
+ RelPath = "Classes\NoVirtualMethodClass.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
- RelPath = "IServiceStatus.cs"
+ RelPath = "Classes\SealedMethodsClass.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
- RelPath = "MyInterfaceImpl.cs"
+ RelPath = "Classes\ServiceClass.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
- RelPath = "MySecondInterfaceImpl.cs"
+ RelPath = "Classes\SpecializedServiceClass.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
- RelPath = "ProxyGeneratorTestCase.cs"
+ RelPath = "ClassInterfaces\IMyInterface.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "ClassInterfaces\IMySecondInterface.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "ClassInterfaces\IServiceStatus.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "ClassInterfaces\MyInterfaceImpl.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "ClassInterfaces\MySecondInterfaceImpl.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
- RelPath = "ServiceStatusImpl.cs"
+ RelPath = "ClassInterfaces\ServiceStatusImpl.cs"
SubType = "Code"
BuildAction = "Compile"
/>
Added: avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/ClassInterfaces/IMyInterface.cs
==============================================================================
--- (empty file)
+++ avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/ClassInterfaces/IMyInterface.cs Mon Sep 6 13:43:16 2004
@@ -0,0 +1,40 @@
+// Copyright 2004 The Apache Software Foundation
+//
+// 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 Apache.Avalon.DynamicProxy.Test.ClassInterfaces
+{
+ using System;
+
+ /// <summary>
+ /// Summary description for IMyInterface.
+ /// </summary>
+ public interface IMyInterface
+ {
+ String Name
+ {
+ get;
+ set;
+ }
+
+ bool Started
+ {
+ get;
+ set;
+ }
+
+ int Calc(int x, int y);
+
+ int Calc(int x, int y, int z, Single k);
+ }
+}
Added: avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/ClassInterfaces/IMySecondInterface.cs
==============================================================================
--- (empty file)
+++ avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/ClassInterfaces/IMySecondInterface.cs Mon Sep 6 13:43:16 2004
@@ -0,0 +1,30 @@
+// Copyright 2004 The Apache Software Foundation
+//
+// 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 Apache.Avalon.DynamicProxy.Test.ClassInterfaces
+{
+ using System;
+
+ /// <summary>
+ /// Summary description for IMySecondInterface.
+ /// </summary>
+ public interface IMySecondInterface : IMyInterface
+ {
+ String Address
+ {
+ get;
+ set;
+ }
+ }
+}
Added: avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/ClassInterfaces/IServiceStatus.cs
==============================================================================
--- (empty file)
+++ avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/ClassInterfaces/IServiceStatus.cs Mon Sep 6 13:43:16 2004
@@ -0,0 +1,45 @@
+// Copyright 2004 The Apache Software Foundation
+//
+// 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 Apache.Avalon.DynamicProxy.Test.ClassInterfaces
+{
+ using System;
+
+ /// <summary>
+ /// Simple enum declaration
+ /// </summary>
+ public enum State
+ {
+ Valid,
+ Invalid
+ }
+
+ /// <summary>
+ /// Summary description for IServiceStatus.
+ /// </summary>
+ public interface IServiceStatus
+ {
+ int Requests
+ {
+ get;
+ }
+
+ State ActualState
+ {
+ get;
+ }
+
+ void ChangeState(State state);
+ }
+}
Added: avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/ClassInterfaces/MyInterfaceImpl.cs
==============================================================================
--- (empty file)
+++ avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/ClassInterfaces/MyInterfaceImpl.cs Mon Sep 6 13:43:16 2004
@@ -0,0 +1,69 @@
+// Copyright 2004 The Apache Software Foundation
+//
+// 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 Apache.Avalon.DynamicProxy.Test.ClassInterfaces
+{
+ using System;
+
+ /// <summary>
+ /// Summary description for MyInterfaceImpl.
+ /// </summary>
+ public class MyInterfaceImpl : IMyInterface
+ {
+ private String m_name;
+ private bool m_started;
+
+ public MyInterfaceImpl()
+ {
+ }
+
+ #region IMyInterface Members
+
+ public String Name
+ {
+ get
+ {
+ return m_name;
+ }
+ set
+ {
+ m_name = value;
+ }
+ }
+
+ public bool Started
+ {
+ get
+ {
+ return m_started;
+ }
+ set
+ {
+ m_started = value;
+ }
+ }
+
+ public int Calc(int x, int y)
+ {
+ return x + y;
+ }
+
+ public int Calc(int x, int y, int z, Single k)
+ {
+ return x + y + z + (int)k;
+ }
+
+ #endregion
+ }
+}
Added: avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/ClassInterfaces/MySecondInterfaceImpl.cs
==============================================================================
--- (empty file)
+++ avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/ClassInterfaces/MySecondInterfaceImpl.cs Mon Sep 6 13:43:16 2004
@@ -0,0 +1,46 @@
+// Copyright 2004 The Apache Software Foundation
+//
+// 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 Apache.Avalon.DynamicProxy.Test.ClassInterfaces
+{
+ using System;
+
+ /// <summary>
+ /// Summary description for MySecondInterfaceImpl.
+ /// </summary>
+ public class MySecondInterfaceImpl : MyInterfaceImpl, IMySecondInterface
+ {
+ private String m_address;
+
+ public MySecondInterfaceImpl()
+ {
+ }
+
+ #region IMySecondInterface Members
+
+ public String Address
+ {
+ get
+ {
+ return m_address;
+ }
+ set
+ {
+ m_address = value;
+ }
+ }
+
+ #endregion
+ }
+}
Added: avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/ClassInterfaces/ServiceStatusImpl.cs
==============================================================================
--- (empty file)
+++ avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/ClassInterfaces/ServiceStatusImpl.cs Mon Sep 6 13:43:16 2004
@@ -0,0 +1,55 @@
+// Copyright 2004 The Apache Software Foundation
+//
+// 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 Apache.Avalon.DynamicProxy.Test.ClassInterfaces
+{
+ using System;
+
+ /// <summary>
+ /// Summary description for ServiceStatusImpl.
+ /// </summary>
+ public class ServiceStatusImpl : IServiceStatus
+ {
+ private State m_state = State.Invalid;
+
+ public ServiceStatusImpl()
+ {
+ }
+
+ #region IServiceStatus Members
+
+ public int Requests
+ {
+ get
+ {
+ return 10;
+ }
+ }
+
+ public State ActualState
+ {
+ get
+ {
+ return m_state;
+ }
+ }
+
+ public void ChangeState(State state)
+ {
+ m_state = state;
+ }
+
+ #endregion
+ }
+}
Added: avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/Classes/NoVirtualMethodClass.cs
==============================================================================
--- (empty file)
+++ avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/Classes/NoVirtualMethodClass.cs Mon Sep 6 13:43:16 2004
@@ -0,0 +1,29 @@
+// Copyright 2004 The Apache Software Foundation
+//
+// 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 Apache.Avalon.DynamicProxy.Test.Classes
+{
+ using System;
+
+ /// <summary>
+ /// Summary description for NoVirtualMethodClass.
+ /// </summary>
+ public class NoVirtualMethodClass
+ {
+ public int Sum(int b1, int b2)
+ {
+ return b1 + b2;
+ }
+ }
+}
Added: avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/Classes/SealedMethodsClass.cs
==============================================================================
--- (empty file)
+++ avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/Classes/SealedMethodsClass.cs Mon Sep 6 13:43:16 2004
@@ -0,0 +1,29 @@
+// Copyright 2004 The Apache Software Foundation
+//
+// 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 Apache.Avalon.DynamicProxy.Test.Classes
+{
+ using System;
+
+ /// <summary>
+ /// Summary description for SealedMethodsClass.
+ /// </summary>
+ public class SealedMethodsClass : ServiceClass
+ {
+ public override sealed int Sum(int b1, int b2)
+ {
+ return b1 + b2;
+ }
+ }
+}
Added: avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/Classes/ServiceClass.cs
==============================================================================
--- (empty file)
+++ avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/Classes/ServiceClass.cs Mon Sep 6 13:43:16 2004
@@ -0,0 +1,74 @@
+ // Copyright 2004 The Apache Software Foundation
+//
+// 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 Apache.Avalon.DynamicProxy.Test.Classes
+{
+ using System;
+
+ /// <summary>
+ /// Summary description for ServiceClass.
+ /// </summary>
+ public class ServiceClass
+ {
+ public virtual int Sum(int b1, int b2)
+ {
+ return b1 + b2;
+ }
+
+ public virtual byte Sum(byte b1, byte b2)
+ {
+ return System.Convert.ToByte( b1 + b2 );
+ }
+
+ public virtual long Sum(long b1, long b2)
+ {
+ return b1 + b2;
+ }
+
+ public virtual short Sum(short b1, short b2)
+ {
+ return (short) (b1 + b2);
+ }
+
+ public virtual float Sum(float b1, float b2)
+ {
+ return b1 + b2;
+ }
+
+ public virtual double Sum(double b1, double b2)
+ {
+ return b1 + b2;
+ }
+
+ public virtual UInt16 Sum(UInt16 b1, UInt16 b2)
+ {
+ return (UInt16) (b1 + b2);
+ }
+
+ public virtual UInt32 Sum(UInt32 b1, UInt32 b2)
+ {
+ return b1 + b2;
+ }
+
+ public virtual UInt64 Sum(UInt64 b1, UInt64 b2)
+ {
+ return b1 + b2;
+ }
+
+ public virtual bool Valid
+ {
+ get { return true; }
+ }
+ }
+}
\ No newline at end of file
Added: avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/Classes/SpecializedServiceClass.cs
==============================================================================
--- (empty file)
+++ avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/Classes/SpecializedServiceClass.cs Mon Sep 6 13:43:16 2004
@@ -0,0 +1,29 @@
+// Copyright 2004 The Apache Software Foundation
+//
+// 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 Apache.Avalon.DynamicProxy.Test.Classes
+{
+ using System;
+
+ /// <summary>
+ /// Summary description for SpecializedServiceClass.
+ /// </summary>
+ public class SpecializedServiceClass : ServiceClass
+ {
+ public virtual int Subtract(int b1, int b2)
+ {
+ return b1 - b2;
+ }
+ }
+}
Modified: avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/ProxyGeneratorTestCase.cs
==============================================================================
--- avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/ProxyGeneratorTestCase.cs (original)
+++ avalon/trunk/central/laboratory/avalon-net/DynamicProxy/DynamicProxyTest/ProxyGeneratorTestCase.cs Mon Sep 6 13:43:16 2004
@@ -20,6 +20,8 @@
using NUnit.Framework;
using Apache.Avalon.DynamicProxy;
+ using Apache.Avalon.DynamicProxy.Test.Classes;
+ using Apache.Avalon.DynamicProxy.Test.ClassInterfaces;
/// <summary>
/// Summary description for ProxyGeneratorTestCase.
@@ -28,6 +30,100 @@
public class ProxyGeneratorTestCase : Assertion
{
[Test]
+ public void ProxyForClass()
+ {
+ object proxy = ProxyGenerator.CreateClassProxy(
+ typeof(ServiceClass), new ResultModifiedInvocationHandler( new ServiceClass() ) );
+
+ AssertNotNull( proxy );
+ Assert( typeof(ServiceClass).IsAssignableFrom( proxy.GetType() ) );
+
+ ServiceClass inter = (ServiceClass) proxy;
+
+ AssertEquals( 44, inter.Sum( 20, 25 ) );
+ AssertEquals( true, inter.Valid );
+ }
+
+ [Test]
+ public void ProxyForClassWithSuperClass()
+ {
+ object proxy = ProxyGenerator.CreateClassProxy(
+ typeof(SpecializedServiceClass), new ResultModifiedInvocationHandler( new SpecializedServiceClass() ) );
+
+ AssertNotNull( proxy );
+ Assert( typeof(ServiceClass).IsAssignableFrom( proxy.GetType() ) );
+ Assert( typeof(SpecializedServiceClass).IsAssignableFrom( proxy.GetType() ) );
+
+ SpecializedServiceClass inter = (SpecializedServiceClass) proxy;
+
+ AssertEquals( 44, inter.Sum( 20, 25 ) );
+ AssertEquals( -6, inter.Subtract( 20, 25 ) );
+ AssertEquals( true, inter.Valid );
+ }
+
+ [Test]
+ public void ProxyingClassWithoutVirtualMethods()
+ {
+ object proxy = ProxyGenerator.CreateClassProxy(
+ typeof(NoVirtualMethodClass), new ResultModifiedInvocationHandler( new SpecializedServiceClass() ) );
+
+ AssertNotNull( proxy );
+ Assert( typeof(NoVirtualMethodClass).IsAssignableFrom( proxy.GetType() ) );
+
+ NoVirtualMethodClass inter = (NoVirtualMethodClass) proxy;
+
+ AssertEquals( 45, inter.Sum( 20, 25 ) );
+ }
+
+ [Test]
+ public void ProxyingClassWithSealedMethods()
+ {
+ object proxy = ProxyGenerator.CreateClassProxy(
+ typeof(SealedMethodsClass), new ResultModifiedInvocationHandler( new SpecializedServiceClass() ) );
+
+ AssertNotNull( proxy );
+ Assert( typeof(SealedMethodsClass).IsAssignableFrom( proxy.GetType() ) );
+
+ SealedMethodsClass inter = (SealedMethodsClass) proxy;
+
+ AssertEquals( 45, inter.Sum( 20, 25 ) );
+ }
+
+ [Test]
+ public void CreateClassProxyInvalidArguments()
+ {
+ try
+ {
+ ProxyGenerator.CreateClassProxy(
+ typeof(ICloneable), new StandardInvocationHandler( new SpecializedServiceClass() ) );
+ }
+ catch(ArgumentException)
+ {
+ // Expected
+ }
+
+ try
+ {
+ ProxyGenerator.CreateClassProxy(
+ null, new StandardInvocationHandler( new SpecializedServiceClass() ) );
+ }
+ catch(ArgumentNullException)
+ {
+ // Expected
+ }
+
+ try
+ {
+ ProxyGenerator.CreateClassProxy(
+ typeof(SpecializedServiceClass), null );
+ }
+ catch(ArgumentNullException)
+ {
+ // Expected
+ }
+ }
+
+ [Test]
public void TestGenerationSimpleInterface()
{
object proxy = ProxyGenerator.CreateProxy(
@@ -98,6 +194,22 @@
#endregion
}
+ }
+
+ public class ResultModifiedInvocationHandler : StandardInvocationHandler
+ {
+ public ResultModifiedInvocationHandler( object instanceDelegate ) : base(instanceDelegate)
+ {
+ }
+
+ protected override void PostInvoke(object proxy, System.Reflection.MethodInfo method, ref object returnValue, params object[] arguments)
+ {
+ if ( returnValue != null && returnValue.GetType() == typeof(int))
+ {
+ int value = (int) returnValue;
+ returnValue = --value;
+ }
+ }
}
}
Modified: avalon/trunk/central/laboratory/avalon-net/DynamicProxy/ProxyGenerator.cs
==============================================================================
--- avalon/trunk/central/laboratory/avalon-net/DynamicProxy/ProxyGenerator.cs (original)
+++ avalon/trunk/central/laboratory/avalon-net/DynamicProxy/ProxyGenerator.cs Mon Sep 6 13:43:16 2004
@@ -1,437 +1,116 @@
-// Copyright 2004 The Apache Software Foundation
-//
-// 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 Apache.Avalon.DynamicProxy
-{
- using System;
- using System.Reflection;
- using System.Reflection.Emit;
-
- /// <summary>
- /// Generates a Java style proxy. This overrides the .Net proxy requirements
- /// that forces one to extend MarshalByRefObject or (for a different purpose)
- /// ContextBoundObject to have a Proxiable class.
- /// </summary>
- /// <remarks>
- /// The <see cref="ProxyGenerator"/> should be used to generate a class
- /// implementing the specified interfaces. The class implementation will
- /// only call the internal <see cref="IInvocationHandler"/> instance.
- /// </remarks>
- /// <remarks>
- /// This proxy implementation currently doesn't not supports ref and out arguments
- /// in methods.
- /// </remarks>
- /// <example>
- /// <code>
- /// MyInvocationHandler handler = ...
- /// IInterfaceExposed proxy =
- /// ProxyGenerator.CreateProxy( new Type[] { typeof(IInterfaceExposed) }, handler );
- /// </code>
- /// </example>
- public class ProxyGenerator
- {
- /// <summary>
- /// Private construtor
- /// </summary>
- private ProxyGenerator()
- {
- }
-
- /// <summary>
- /// Generates a proxy implementing all the specified interfaces and
- /// redirecting method invocations to the specifed handler.
- /// </summary>
- /// <param name="theInterface">Interface to be implemented</param>
- /// <param name="handler">instance of <see cref="IInvocationHandler"/></param>
- /// <returns>Proxy instance</returns>
- public static object CreateProxy(Type theInterface, IInvocationHandler handler)
- {
- return CreateProxy(new Type[] { theInterface }, handler );
- }
-
- /// <summary>
- /// Generates a proxy implementing all the specified interfaces and
- /// redirecting method invocations to the specifed handler.
- /// </summary>
- /// <param name="interfaces">Array of interfaces to be implemented</param>
- /// <param name="handler">instance of <see cref="IInvocationHandler"/></param>
- /// <returns>Proxy instance</returns>
- public static object CreateProxy(Type[] interfaces, IInvocationHandler handler)
- {
- if (interfaces == null)
- {
- throw new ArgumentNullException("interfaces");
- }
- if (handler == null)
- {
- throw new ArgumentNullException("handler");
- }
- if (interfaces.Length == 0)
- {
- throw new ArgumentException("Can't handle an empty interface array");
- }
-
- AssemblyName assemblyName = new AssemblyName();
- assemblyName.Name = "DynamicAssemblyProxyGen";
-
- AssemblyBuilder assemblyBuilder =
- AppDomain.CurrentDomain.DefineDynamicAssembly(
- assemblyName,
- AssemblyBuilderAccess.Run);
-
- ModuleBuilder moduleBuilder =
- assemblyBuilder.DefineDynamicModule( assemblyName.Name, true );
-
- TypeBuilder typeBuilder = moduleBuilder.DefineType(
- "ProxyType", TypeAttributes.Public|TypeAttributes.Class, null, interfaces);
-
- FieldBuilder handlerField = GenerateField( typeBuilder );
- ConstructorBuilder constr = GenerateConstructor( typeBuilder, handlerField );
-
- GenerateInterfaceImplementation( typeBuilder, interfaces, handlerField );
-
- Type generatedType = typeBuilder.CreateType();
-
- return Activator.CreateInstance( generatedType, new object[] { handler } );
- }
-
- /// <summary>
- ///
- /// </summary>
- /// <param name="typeBuilder"></param>
- /// <param name="interfaces"></param>
- private static void GenerateInterfaceImplementation( TypeBuilder typeBuilder,
- Type[] interfaces, FieldBuilder handlerField )
- {
- foreach(Type inter in interfaces)
- {
- GenerateInterfaceImplementation( typeBuilder, inter, handlerField );
- }
- }
-
- /// <summary>
- /// Iterates over the interfaces and generate implementation
- /// for each method in it.
- /// </summary>
- /// <param name="typeBuilder"><see cref="TypeBuilder"/> being constructed.</param>
- /// <param name="inter">Interface type</param>
- private static void GenerateInterfaceImplementation( TypeBuilder typeBuilder,
- Type inter, FieldBuilder handlerField )
- {
- if (!inter.IsInterface)
- {
- throw new ArgumentException("Type array expects interfaces only.");
- }
-
- Type[] baseInterfaces = inter.FindInterfaces( new TypeFilter( NoFilterImpl ), inter );
-
- GenerateInterfaceImplementation( typeBuilder, baseInterfaces, handlerField );
-
- PropertyInfo[] properties = inter.GetProperties();
- PropertyBuilder[] propertiesBuilder = new PropertyBuilder[properties.Length];
-
- for(int i=0; i < properties.Length; i++)
- {
- GeneratePropertyImplementation( typeBuilder, properties[i], ref propertiesBuilder[i] );
- }
-
- MethodInfo[] methods = inter.GetMethods();
-
- foreach(MethodInfo method in methods)
- {
- GenerateMethodImplementation( typeBuilder, method,
- propertiesBuilder, handlerField, inter );
- }
- }
-
- /// <summary>
- /// Generates a public field holding the <see cref="IInvocationHandler"/>
- /// </summary>
- /// <param name="typeBuilder"><see cref="TypeBuilder"/> being constructed.</param>
- /// <returns><see cref="FieldBuilder"/> instance</returns>
- private static FieldBuilder GenerateField( TypeBuilder typeBuilder )
- {
- return typeBuilder.DefineField( "handler",
- typeof(IInvocationHandler), FieldAttributes.Public );
- }
-
- /// <summary>
- /// Generates one public constructor receiving
- /// the <see cref="IInvocationHandler"/> instance.
- /// </summary>
- /// <param name="typeBuilder"><see cref="TypeBuilder"/> being constructed.</param>
- /// <param name="handlerField"><see cref="FieldBuilder"/> instance representing the handler field</param>
- /// <returns><see cref="ConstructorBuilder"/> instance</returns>
- private static ConstructorBuilder GenerateConstructor(
- TypeBuilder typeBuilder, FieldBuilder handlerField )
- {
- ConstructorBuilder consBuilder = typeBuilder.DefineConstructor(
- MethodAttributes.Public,
- CallingConventions.Standard,
- new Type[] { typeof(IInvocationHandler) } );
-
- ILGenerator ilGenerator = consBuilder.GetILGenerator();
- ilGenerator.Emit(OpCodes.Ldarg_0);
- ilGenerator.Emit(OpCodes.Call, typeof(Object).GetConstructor(new Type[0]));
- ilGenerator.Emit(OpCodes.Ldarg_0);
- ilGenerator.Emit(OpCodes.Ldarg_1);
- ilGenerator.Emit(OpCodes.Stfld, handlerField);
- ilGenerator.Emit(OpCodes.Ret);
-
- return consBuilder;
- }
-
- /// <summary>
- /// Generate property implementation
- /// </summary>
- /// <param name="typeBuilder"><see cref="TypeBuilder"/> being constructed.</param>
- /// <param name="property"></param>
- /// <param name="propertyBuilder"></param>
- private static void GeneratePropertyImplementation(
- TypeBuilder typeBuilder, PropertyInfo property, ref PropertyBuilder propertyBuilder )
- {
- propertyBuilder = typeBuilder.DefineProperty(
- property.Name, property.Attributes, property.PropertyType, null);
- }
-
- /// <summary>
- /// Generates implementation for each method.
- /// </summary>
- /// <param name="typeBuilder"><see cref="TypeBuilder"/> being constructed.</param>
- /// <param name="method"></param>
- /// <param name="properties"></param>
- private static void GenerateMethodImplementation(
- TypeBuilder typeBuilder, MethodInfo method,
- PropertyBuilder[] properties, FieldBuilder handlerField, Type inter )
- {
- ParameterInfo[] parameterInfo = method.GetParameters();
-
- System.Type[] parameters = new System.Type[parameterInfo.Length];
-
- for (int i=0; i<parameterInfo.Length; i++)
- {
- parameters[i] = parameterInfo[i].ParameterType;
- }
-
- MethodAttributes atts = MethodAttributes.Public|MethodAttributes.Virtual;
-
- if ( method.Name.StartsWith("set_") || method.Name.StartsWith("get_") )
- {
- atts = MethodAttributes.Public|MethodAttributes.SpecialName|MethodAttributes.Virtual;
- }
-
- MethodBuilder methodBuilder =
- typeBuilder.DefineMethod( method.Name, atts, CallingConventions.Standard,
- method.ReturnType, parameters );
-
- if ( method.Name.StartsWith("set_") || method.Name.StartsWith("get_") )
- {
- foreach( PropertyBuilder property in properties )
- {
- if (property == null)
- {
- break;
- }
-
- if (!property.Name.Equals( method.Name.Substring(4) ))
- {
- continue;
- }
-
- if ( methodBuilder.Name.StartsWith("set_") )
- {
- property.SetSetMethod( methodBuilder );
- break;
- }
- else
- {
- property.SetGetMethod( methodBuilder );
- break;
- }
- }
- }
-
- WriteILForMethod( method, methodBuilder, parameters, handlerField );
- }
-
- /// <summary>
- /// Writes the stack for the method implementation. This
- /// method generates the IL stack for property get/set method and
- /// ordinary methods.
- /// </summary>
- /// <remarks>
- /// The method implementation would be as simple as:
- /// <code>
- /// public void SomeMethod( int parameter )
- /// {
- /// MethodBase method = MethodBase.GetCurrentMethod();
- /// handler.Invoke( this, method, new object[] { parameter } );
- /// }
- /// </code>
- /// </remarks>
- /// <param name="typeBuilder"><see cref="TypeBuilder"/> being constructed.</param>
- /// <param name="parameters"></param>
- /// <param name="handlerField"></param>
- private static void WriteILForMethod( MethodInfo method, MethodBuilder builder,
- System.Type[] parameters, FieldBuilder handlerField )
- {
- int arrayPositionInStack = 1;
-
- ILGenerator ilGenerator = builder.GetILGenerator();
-
- ilGenerator.DeclareLocal( typeof( MethodBase ) );
-
- if (builder.ReturnType != typeof(void))
- {
- ilGenerator.DeclareLocal(builder.ReturnType);
- arrayPositionInStack = 2;
- }
-
- ilGenerator.DeclareLocal( typeof(object[]) );
-
- ilGenerator.Emit(OpCodes.Ldtoken, method);
- ilGenerator.Emit(OpCodes.Call, typeof(MethodBase).GetMethod("GetMethodFromHandle"));
-
- ilGenerator.Emit(OpCodes.Stloc_0);
- ilGenerator.Emit(OpCodes.Ldarg_0);
- ilGenerator.Emit(OpCodes.Ldfld, handlerField);
- ilGenerator.Emit(OpCodes.Ldarg_0);
- ilGenerator.Emit(OpCodes.Ldloc_0);
- ilGenerator.Emit(OpCodes.Ldc_I4, parameters.Length);
- ilGenerator.Emit(OpCodes.Newarr, typeof(object) );
-
- if (parameters.Length != 0)
- {
- ilGenerator.Emit(OpCodes.Stloc, arrayPositionInStack);
- ilGenerator.Emit(OpCodes.Ldloc, arrayPositionInStack);
- }
-
- for (int c=0; c<parameters.Length; c++)
- {
- ilGenerator.Emit(OpCodes.Ldc_I4, c);
- ilGenerator.Emit(OpCodes.Ldarg, c+1);
-
- if (parameters[c].IsValueType)
- {
- ilGenerator.Emit(OpCodes.Box, parameters[c].UnderlyingSystemType);
- }
-
- ilGenerator.Emit(OpCodes.Stelem_Ref);
- ilGenerator.Emit(OpCodes.Ldloc, arrayPositionInStack);
- }
-
- ilGenerator.Emit(OpCodes.Callvirt, typeof(IInvocationHandler).GetMethod("Invoke") );
-
- if (builder.ReturnType != typeof(void))
- {
- if (!builder.ReturnType.IsValueType)
- {
- ilGenerator.Emit(OpCodes.Castclass, builder.ReturnType);
- }
- else
- {
- ilGenerator.Emit(OpCodes.Unbox, builder.ReturnType);
- ilGenerator.Emit(ConvertTypeToOpCode(builder.ReturnType));
- }
-
- ilGenerator.Emit(OpCodes.Stloc, 1);
-
- Label label = ilGenerator.DefineLabel();
- ilGenerator.Emit(OpCodes.Br_S, label);
- ilGenerator.MarkLabel(label);
- ilGenerator.Emit(OpCodes.Ldloc, 1);
- }
- else
- {
- ilGenerator.Emit(OpCodes.Pop);
- }
-
- ilGenerator.Emit(OpCodes.Ret);
- }
-
- /// <summary>
- /// Converts a Value type to a correspondent OpCode of
- /// </summary>
- /// <param name="type"></param>
- /// <returns></returns>
- private static OpCode ConvertTypeToOpCode( Type type )
- {
- if (type.IsEnum)
- {
- System.Enum baseType = (System.Enum) Activator.CreateInstance( type );
- TypeCode code = baseType.GetTypeCode();
-
- switch(code)
- {
- case TypeCode.Byte:
- type = typeof(Byte);
- break;
- case TypeCode.Int16:
- type = typeof(Int16);
- break;
- case TypeCode.Int32:
- type = typeof(Int32);
- break;
- case TypeCode.Int64:
- type = typeof(Int64);
- break;
- }
-
- return ConvertTypeToOpCode( type );
- }
-
- if ( type.Equals( typeof(Int32) ) )
- {
- return OpCodes.Ldind_I4;
- }
- else if ( type.Equals( typeof(Int16) ) )
- {
- return OpCodes.Ldind_I2;
- }
- else if ( type.Equals( typeof(Int64) ) )
- {
- return OpCodes.Ldind_I8;
- }
- else if ( type.Equals( typeof(Single) ) )
- {
- return OpCodes.Ldind_R4;
- }
- else if ( type.Equals( typeof(Double) ) )
- {
- return OpCodes.Ldind_R8;
- }
- else if ( type.Equals( typeof(UInt16) ) )
- {
- return OpCodes.Ldind_U2;
- }
- else if ( type.Equals( typeof(UInt32) ) )
- {
- return OpCodes.Ldind_U4;
- }
- else if ( type.Equals( typeof(Boolean) ) )
- {
- return OpCodes.Ldind_I4;
- }
- else
- {
- throw new ArgumentException("Type " + type + " could not be converted to a OpCode");
- }
- }
-
- public static bool NoFilterImpl( Type type, object criteria )
- {
- return true;
- }
- }
-}
+ // Copyright 2004 The Apache Software Foundation
+//
+// 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 Apache.Avalon.DynamicProxy
+{
+ using System;
+ using System.Reflection;
+ using System.Reflection.Emit;
+
+ using Apache.Avalon.DynamicProxy.Builder;
+
+ /// <summary>
+ /// Generates a Java style proxy. This overrides the .Net proxy requirements
+ /// that forces one to extend MarshalByRefObject or (for a different purpose)
+ /// ContextBoundObject to have a Proxiable class.
+ /// </summary>
+ /// <remarks>
+ /// The <see cref="ProxyGenerator"/> should be used to generate a class
+ /// implementing the specified interfaces. The class implementation will
+ /// only call the internal <see cref="IInvocationHandler"/> instance.
+ /// </remarks>
+ /// <remarks>
+ /// This proxy implementation currently doesn't not supports ref and out arguments
+ /// in methods.
+ /// </remarks>
+ /// <example>
+ /// <code>
+ /// MyInvocationHandler handler = ...
+ /// IInterfaceExposed proxy =
+ /// ProxyGenerator.CreateProxy( new Type[] { typeof(IInterfaceExposed) }, handler );
+ /// </code>
+ /// </example>
+ public abstract class ProxyGenerator
+ {
+ private static IProxyBuilder m_builder = new ProxyBuilderImpl();
+
+ public static IProxyBuilder ProxyBuilder
+ {
+ get { return m_builder; }
+ set { m_builder = value; }
+ }
+
+ public static object CreateClassProxy(Type baseClass, IInvocationHandler handler)
+ {
+ if (baseClass == null)
+ {
+ throw new ArgumentNullException("theClass");
+ }
+ if (baseClass.IsInterface)
+ {
+ throw new ArgumentException("'baseClass' must be a class, not an interface");
+ }
+ if (handler == null)
+ {
+ throw new ArgumentNullException("handler");
+ }
+
+ Type newType = ProxyBuilder.CreateClassProxy(baseClass);
+ return CreateProxyInstance( newType, handler );
+ }
+
+ /// <summary>
+ /// Generates a proxy implementing all the specified interfaces and
+ /// redirecting method invocations to the specifed handler.
+ /// </summary>
+ /// <param name="theInterface">Interface to be implemented</param>
+ /// <param name="handler">instance of <see cref="IInvocationHandler"/></param>
+ /// <returns>Proxy instance</returns>
+ public static object CreateProxy(Type theInterface, IInvocationHandler handler)
+ {
+ return CreateProxy(new Type[] {theInterface}, handler);
+ }
+
+ /// <summary>
+ /// Generates a proxy implementing all the specified interfaces and
+ /// redirecting method invocations to the specifed handler.
+ /// </summary>
+ /// <param name="interfaces">Array of interfaces to be implemented</param>
+ /// <param name="handler">instance of <see cref="IInvocationHandler"/></param>
+ /// <returns>Proxy instance</returns>
+ public static object CreateProxy(Type[] interfaces, IInvocationHandler handler)
+ {
+ if (interfaces == null)
+ {
+ throw new ArgumentNullException("interfaces");
+ }
+ if (handler == null)
+ {
+ throw new ArgumentNullException("handler");
+ }
+ if (interfaces.Length == 0)
+ {
+ throw new ArgumentException("Can't handle an empty interface array");
+ }
+
+ Type newType = ProxyBuilder.CreateInterfaceProxy(interfaces);
+ return CreateProxyInstance( newType, handler );
+ }
+
+ private static object CreateProxyInstance(Type type, IInvocationHandler handler)
+ {
+ return Activator.CreateInstance(type, new object[] {handler});
+ }
+ }
+}
\ No newline at end of file