diff --git a/src/Spring/Spring.Core/Expressions/IndexerNode.cs b/src/Spring/Spring.Core/Expressions/IndexerNode.cs
index 730de743..e1ce7367 100644
--- a/src/Spring/Spring.Core/Expressions/IndexerNode.cs
+++ b/src/Spring/Spring.Core/Expressions/IndexerNode.cs
@@ -40,7 +40,7 @@ namespace Spring.Expressions
| BindingFlags.Instance | BindingFlags.Static
| BindingFlags.IgnoreCase;
- private SafeIndexer indexer;
+ private SafeProperty indexer;
///
/// Create a new instance
@@ -191,7 +191,7 @@ namespace Spring.Expressions
EvaluationContext evalContext = new EvaluationContext(context, variables);
InitializeIndexerProperty(context, evalContext);
- return indexer.IndexerProperty;
+ return indexer.PropertyInfo;
}
}
@@ -260,7 +260,7 @@ namespace Spring.Expressions
private void SetGenericIndexer(object context, EvaluationContext evalContext,object newValue)
{
object[] indices = InitializeIndexerProperty( context, evalContext );
- indexer.SetValue( context,indices,newValue );
+ indexer.SetValue( context, newValue, indices );
}
private object[] InitializeIndexerProperty(object context, EvaluationContext evalContext)
@@ -281,7 +281,7 @@ namespace Spring.Expressions
}
else
{
- indexer = new SafeIndexer(indexerProperty);
+ indexer = new SafeProperty(indexerProperty);
}
}
}
diff --git a/src/Spring/Spring.Core/Reflection/Dynamic/BaseDynamicMember.cs b/src/Spring/Spring.Core/Reflection/Dynamic/BaseDynamicMember.cs
index 4dafbefd..10e4e865 100644
--- a/src/Spring/Spring.Core/Reflection/Dynamic/BaseDynamicMember.cs
+++ b/src/Spring/Spring.Core/Reflection/Dynamic/BaseDynamicMember.cs
@@ -34,6 +34,8 @@ namespace Spring.Reflection.Dynamic
/// Aleksandar Seovic
public class BaseDynamicMember
{
+//#if NET_2_0
+//#else
///
/// Method attributes constant.
///
@@ -56,12 +58,12 @@ namespace Spring.Reflection.Dynamic
if (targetType.IsValueType)
{
LocalBuilder target = il.DeclareLocal(targetType);
-#if NET_2_0
- il.Emit(OpCodes.Unbox_Any, targetType);
-#else
+//#if NET_2_0
+// il.Emit(OpCodes.Unbox_Any, targetType);
+//#else
il.Emit(OpCodes.Unbox, targetType);
il.Emit(OpCodes.Ldobj, targetType);
-#endif
+//#endif
il.Emit(OpCodes.Stloc, target);
il.Emit(OpCodes.Ldloca, target);
}
@@ -82,12 +84,12 @@ namespace Spring.Reflection.Dynamic
il.Emit(OpCodes.Ldarg, argumentPosition);
if (argumentType.IsValueType)
{
-#if NET_2_0
- il.Emit(OpCodes.Unbox_Any, argumentType);
-#else
+//#if NET_2_0
+// il.Emit(OpCodes.Unbox_Any, argumentType);
+//#else
il.Emit(OpCodes.Unbox, argumentType);
il.Emit(OpCodes.Ldobj, argumentType);
-#endif
+//#endif
}
else
{
@@ -142,5 +144,6 @@ namespace Spring.Reflection.Dynamic
il.Emit(OpCodes.Newobj, invalidOperationException);
il.Emit(OpCodes.Throw);
}
+//#endif
}
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Core/Reflection/Dynamic/DynamicConstructor.cs b/src/Spring/Spring.Core/Reflection/Dynamic/DynamicConstructor.cs
index f34d0e22..9772b183 100644
--- a/src/Spring/Spring.Core/Reflection/Dynamic/DynamicConstructor.cs
+++ b/src/Spring/Spring.Core/Reflection/Dynamic/DynamicConstructor.cs
@@ -21,6 +21,7 @@
#region Imports
using System;
+using System.Collections;
using System.Reflection;
using System.Reflection.Emit;
using Spring.Util;
@@ -62,7 +63,59 @@ namespace Spring.Reflection.Dynamic
///
public class SafeConstructor : IDynamicConstructor
{
- private ConstructorInfo constructor;
+ private ConstructorInfo constructorInfo;
+
+#if NET_2_0
+ #region Generated Function Cache
+
+ private static readonly IDictionary constructorCache = new Hashtable();
+
+ ///
+ /// Obtains cached constructor info or creates a new entry, if none is found.
+ ///
+ private static ConstructorDelegate GetOrCreateDynamicConstructor(ConstructorInfo constructorInfo)
+ {
+ ConstructorDelegate method = (ConstructorDelegate)constructorCache[constructorInfo];
+ if (method == null)
+ {
+ method = DynamicReflectionManager.CreateConstructor(constructorInfo);
+ lock (constructorCache)
+ {
+ constructorCache[constructorInfo] = method;
+ }
+ }
+ return method;
+ }
+
+ #endregion
+
+ private ConstructorDelegate constructor;
+
+ ///
+ /// Creates a new instance of the safe constructor wrapper.
+ ///
+ /// Constructor to wrap.
+ public SafeConstructor(ConstructorInfo constructorInfo)
+ {
+ this.constructorInfo = constructorInfo;
+ this.constructor = GetOrCreateDynamicConstructor(constructorInfo);
+ }
+
+
+ ///
+ /// Invokes dynamic constructor.
+ ///
+ ///
+ /// Constructor arguments.
+ ///
+ ///
+ /// A constructor value.
+ ///
+ public object Invoke(object[] arguments)
+ {
+ return constructor(arguments);
+ }
+#else
private IDynamicConstructor dynamicConstructor;
private bool isOptimized = false;
@@ -72,7 +125,7 @@ namespace Spring.Reflection.Dynamic
/// Constructor to wrap.
public SafeConstructor(ConstructorInfo constructor)
{
- this.constructor = constructor;
+ this.constructorInfo = constructor;
if (constructor.IsPublic &&
ReflectionUtils.IsTypeVisible(constructor.DeclaringType, DynamicReflectionManager.ASSEMBLY_NAME))
{
@@ -80,7 +133,7 @@ namespace Spring.Reflection.Dynamic
this.isOptimized = true;
}
}
-
+
///
/// Invokes dynamic constructor.
///
@@ -103,18 +156,40 @@ namespace Spring.Reflection.Dynamic
catch (InvalidCastException)
{
isOptimized = false;
- return constructor.Invoke(arguments);
+ return constructorInfo.Invoke(arguments);
}
}
else
{
- return constructor.Invoke(arguments);
+ return constructorInfo.Invoke(arguments);
}
}
+#endif
}
#endregion
+
+#if NET_2_0
+ ///
+ /// Factory class for dynamic constructors.
+ ///
+ /// Aleksandar Seovic
+ public class DynamicConstructor : BaseDynamicMember
+ {
+ ///
+ /// Creates dynamic constructor instance for the specified .
+ ///
+ /// Constructor info to create dynamic constructor for.
+ /// Dynamic constructor for the specified .
+ public static IDynamicConstructor Create(ConstructorInfo constructorInfo)
+ {
+ AssertUtils.ArgumentNotNull(constructorInfo, "You cannot create a dynamic constructor for a null value.");
+
+ return new SafeConstructor(constructorInfo);
+ }
+ }
+#else
///
/// Factory class for dynamic constructors.
///
@@ -162,37 +237,9 @@ namespace Spring.Reflection.Dynamic
ILGenerator il = invokeMethod.GetILGenerator();
- Type[] argTypes = ReflectionUtils.GetParameterTypes(constructor);
- for (int i = 0; i < argTypes.Length; i++)
- {
- SetupConstructorArgument(il, argTypes[i], i);
- }
-
- il.Emit(OpCodes.Newobj, constructor);
- ProcessReturnValue(il, constructor.DeclaringType);
- il.Emit(OpCodes.Ret);
- }
-
- private static void SetupConstructorArgument(ILGenerator il, Type argumentType, int argumentPosition)
- {
- il.Emit(OpCodes.Ldarg_1);
- il.Emit(OpCodes.Ldc_I4, argumentPosition);
- il.Emit(OpCodes.Ldelem_Ref);
- if (argumentType.IsValueType)
- {
-#if NET_2_0
- il.Emit(OpCodes.Unbox_Any, argumentType);
-#else
- il.Emit(OpCodes.Unbox, argumentType);
- il.Emit(OpCodes.Ldobj, argumentType);
-#endif
- }
- else
- {
- il.Emit(OpCodes.Castclass, argumentType);
- }
- }
-
+ DynamicReflectionManager.EmitInvokeConstructor(il, constructor, true);
+ }
#endregion
}
+#endif
}
diff --git a/src/Spring/Spring.Core/Reflection/Dynamic/DynamicField.cs b/src/Spring/Spring.Core/Reflection/Dynamic/DynamicField.cs
index 4c0f4710..b5af7cc2 100644
--- a/src/Spring/Spring.Core/Reflection/Dynamic/DynamicField.cs
+++ b/src/Spring/Spring.Core/Reflection/Dynamic/DynamicField.cs
@@ -85,10 +85,10 @@ namespace Spring.Reflection.Dynamic
///
private class DynamicFieldCacheEntry
{
- public readonly GetterDelegate Getter;
- public readonly SetterDelegate Setter;
+ public readonly FieldGetterDelegate Getter;
+ public readonly FieldSetterDelegate Setter;
- public DynamicFieldCacheEntry(GetterDelegate getter, SetterDelegate setter)
+ public DynamicFieldCacheEntry(FieldGetterDelegate getter, FieldSetterDelegate setter)
{
Getter = getter;
Setter = setter;
@@ -114,8 +114,8 @@ namespace Spring.Reflection.Dynamic
#endregion
- private readonly GetterDelegate getter;
- private readonly SetterDelegate setter;
+ private readonly FieldGetterDelegate getter;
+ private readonly FieldSetterDelegate setter;
///
/// Creates a new instance of the safe field wrapper.
diff --git a/src/Spring/Spring.Core/Reflection/Dynamic/DynamicIndexer.cs b/src/Spring/Spring.Core/Reflection/Dynamic/DynamicIndexer.cs
index 8f706155..62ee7ca4 100644
--- a/src/Spring/Spring.Core/Reflection/Dynamic/DynamicIndexer.cs
+++ b/src/Spring/Spring.Core/Reflection/Dynamic/DynamicIndexer.cs
@@ -1,5 +1,5 @@
-#region License
-
+#region License
+
/*
* Copyright © 2002-2007 the original author or authors.
*
@@ -14,128 +14,280 @@
* 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.
- */
+ */
+
+#endregion
+
+#region Imports
+
+using System;
+using System.Collections;
+using System.Reflection;
+using System.Reflection.Emit;
+using Spring.Reflection.Dynamic;
+using Spring.Util;
+
+#endregion
+
+namespace Spring.Reflection.Dynamic
+{
+ #region IDynamicIndexer interface
+
+ ///
+ /// Defines methods that dynamic indexer class has to implement.
+ ///
+ public interface IDynamicIndexer
+ {
+ ///
+ /// Gets the value of the dynamic indexer for the specified target object.
+ ///
+ ///
+ /// Target object to get the indexer value from.
+ ///
+ ///
+ /// Indexer argument.
+ ///
+ ///
+ /// A indexer value.
+ ///
+ object GetValue( object target, int index );
+
+ ///
+ /// Gets the value of the dynamic indexer for the specified target object.
+ ///
+ ///
+ /// Target object to get the indexer value from.
+ ///
+ ///
+ /// Indexer argument.
+ ///
+ ///
+ /// A indexer value.
+ ///
+ object GetValue( object target, object index );
+
+ ///
+ /// Gets the value of the dynamic indexer for the specified target object.
+ ///
+ ///
+ /// Target object to get the indexer value from.
+ ///
+ ///
+ /// Indexer arguments.
+ ///
+ ///
+ /// A indexer value.
+ ///
+ object GetValue( object target, object[] index );
+
+ ///
+ /// Gets the value of the dynamic indexer for the specified target object.
+ ///
+ ///
+ /// Target object to set the indexer value on.
+ ///
+ ///
+ /// Indexer argument.
+ ///
+ ///
+ /// A new indexer value.
+ ///
+ void SetValue( object target, int index, object value );
+
+ ///
+ /// Gets the value of the dynamic indexer for the specified target object.
+ ///
+ ///
+ /// Target object to set the indexer value on.
+ ///
+ ///
+ /// Indexer argument.
+ ///
+ ///
+ /// A new indexer value.
+ ///
+ void SetValue( object target, object index, object value );
+
+ ///
+ /// Gets the value of the dynamic indexer for the specified target object.
+ ///
+ ///
+ /// Target object to set the indexer value on.
+ ///
+ ///
+ /// Indexer arguments.
+ ///
+ ///
+ /// A new indexer value.
+ ///
+ void SetValue( object target, object[] index, object value );
+ }
+
+ #endregion
+
+ #region Safe wrapper
+
+#if NET_2_0
+ ///
+ /// Safe wrapper for the dynamic indexer.
+ ///
+ ///
+ /// will attempt to use dynamic
+ /// indexer if possible, but it will fall back to standard
+ /// reflection if necessary.
+ ///
+ [Obsolete("Use SafeProperty instead", false)]
+ public class SafeIndexer : IDynamicIndexer
+ {
+ private PropertyInfo indexerProperty;
+
+ ///
+ /// Internal PropertyInfo accessor.
+ ///
+ internal PropertyInfo IndexerProperty
+ {
+ get { return indexerProperty; }
+ }
+
+ private SafeProperty property;
+
+ ///
+ /// Creates a new instance of the safe indexer wrapper.
+ ///
+ /// Indexer to wrap.
+ public SafeIndexer( PropertyInfo indexerInfo )
+ {
+ AssertUtils.ArgumentNotNull( indexerInfo, "You cannot create a dynamic indexer for a null value." );
+
+ this.indexerProperty = indexerInfo;
+ this.property = new SafeProperty( indexerInfo );
+ }
+
+ ///
+ /// Gets the value of the dynamic indexer for the specified target object.
+ ///
+ ///
+ /// Target object to get indexer value from.
+ ///
+ ///
+ /// Indexer arguments.
+ ///
+ ///
+ /// A indexer value.
+ ///
+ public object GetValue( object target, int index )
+ {
+ return property.GetValue( target, index );
+ }
+
+ ///
+ /// Gets the value of the dynamic indexer for the specified target object.
+ ///
+ ///
+ /// Target object to get the indexer value from.
+ ///
+ ///
+ /// Indexer argument.
+ ///
+ ///
+ /// A indexer value.
+ ///
+ public object GetValue( object target, object index )
+ {
+ return property.GetValue( target, index );
+ }
+
+ ///
+ /// Gets the value of the dynamic indexer for the specified target object.
+ ///
+ ///
+ /// Target object to get indexer value from.
+ ///
+ ///
+ /// Indexer arguments.
+ ///
+ ///
+ /// A indexer value.
+ ///
+ public object GetValue( object target, object[] index )
+ {
+ return property.GetValue( target, index );
+ }
+
+ ///
+ /// Sets the value of the dynamic indexer for the specified target object.
+ ///
+ ///
+ /// Target object to set indexer value on.
+ ///
+ ///
+ /// Indexer arguments.
+ ///
+ ///
+ /// A new indexer value.
+ ///
+ public void SetValue( object target, int index, object value )
+ {
+ property.SetValue( target, value, index );
+ }
+
+ ///
+ /// Sets the value of the dynamic indexer for the specified target object.
+ ///
+ ///
+ /// Target object to set indexer value on.
+ ///
+ ///
+ /// Indexer arguments.
+ ///
+ ///
+ /// A new indexer value.
+ ///
+ public void SetValue( object target, object index, object value )
+ {
+ property.SetValue( target, value, index );
+ }
+
+ ///
+ /// Sets the value of the dynamic indexer for the specified target object.
+ ///
+ ///
+ /// Target object to set indexer value on.
+ ///
+ ///
+ /// Indexer arguments.
+ ///
+ ///
+ /// A new indexer value.
+ ///
+ public void SetValue( object target, object[] index, object value )
+ {
+ property.SetValue( target, value, index );
+ }
+ }
+
+#else
-#endregion
+ ///
+ /// Safe wrapper for the dynamic indexer.
+ ///
+ ///
+ /// will attempt to use dynamic
+ /// indexer if possible, but it will fall back to standard
+ /// reflection if necessary.
+ ///
+ public class SafeIndexer : IDynamicIndexer
+ {
+ private PropertyInfo indexerProperty;
+
+ ///
+ /// Internal PropertyInfo accessor.
+ ///
+ internal PropertyInfo IndexerProperty
+ {
+ get { return indexerProperty; }
+ }
-#region Imports
-
-using System;
-using System.Reflection;
-using System.Reflection.Emit;
-using Spring.Util;
-
-#endregion
-
-namespace Spring.Reflection.Dynamic
-{
- #region IDynamicIndexer interface
-
- ///
- /// Defines methods that dynamic indexer class has to implement.
- ///
- public interface IDynamicIndexer
- {
- ///
- /// Gets the value of the dynamic indexer for the specified target object.
- ///
- ///
- /// Target object to get the indexer value from.
- ///
- ///
- /// Indexer argument.
- ///
- ///
- /// A indexer value.
- ///
- object GetValue(object target, int index);
-
- ///
- /// Gets the value of the dynamic indexer for the specified target object.
- ///
- ///
- /// Target object to get the indexer value from.
- ///
- ///
- /// Indexer argument.
- ///
- ///
- /// A indexer value.
- ///
- object GetValue(object target, object index);
-
- ///
- /// Gets the value of the dynamic indexer for the specified target object.
- ///
- ///
- /// Target object to get the indexer value from.
- ///
- ///
- /// Indexer arguments.
- ///
- ///
- /// A indexer value.
- ///
- object GetValue(object target, object[] index);
-
- ///
- /// Gets the value of the dynamic indexer for the specified target object.
- ///
- ///
- /// Target object to set the indexer value on.
- ///
- ///
- /// Indexer argument.
- ///
- ///
- /// A new indexer value.
- ///
- void SetValue(object target, int index, object value);
-
- ///
- /// Gets the value of the dynamic indexer for the specified target object.
- ///
- ///
- /// Target object to set the indexer value on.
- ///
- ///
- /// Indexer argument.
- ///
- ///
- /// A new indexer value.
- ///
- void SetValue(object target, object index, object value);
-
- ///
- /// Gets the value of the dynamic indexer for the specified target object.
- ///
- ///
- /// Target object to set the indexer value on.
- ///
- ///
- /// Indexer arguments.
- ///
- ///
- /// A new indexer value.
- ///
- void SetValue(object target, object[] index, object value);
- }
-
- #endregion
-
- #region Safe wrapper
-
- ///
- /// Safe wrapper for the dynamic indexer.
- ///
- ///
- /// will attempt to use dynamic
- /// indexer if possible, but it will fall back to standard
- /// reflection if necessary.
- ///
- public class SafeIndexer : IDynamicIndexer
- {
- private PropertyInfo indexerProperty;
private IDynamicIndexer dynamicIndexer;
private bool isOptimizedGet = false;
private bool isOptimizedSet = false;
@@ -334,18 +486,38 @@ namespace Spring.Reflection.Dynamic
indexerProperty.SetValue(target, value, index);
}
}
-
- ///
- /// Internal PropertyInfo accessor.
- ///
- internal PropertyInfo IndexerProperty
- {
- get { return indexerProperty; }
- }
- }
-
- #endregion
-
+ }
+#endif
+
+ #endregion
+
+#if NET_2_0
+ ///
+ /// Factory class for dynamic indexers.
+ ///
+ /// Aleksandar Seovic
+ [Obsolete( "Use DynamicProperty instead", false )]
+ public sealed class DynamicIndexer : BaseDynamicMember
+ {
+ ///
+ /// Prevent instantiation
+ ///
+ private DynamicIndexer() { }
+
+ ///
+ /// Creates dynamic indexer instance for the specified .
+ ///
+ /// Indexer info to create dynamic indexer for.
+ /// Dynamic indexer for the specified .
+ public static IDynamicIndexer Create( PropertyInfo indexer )
+ {
+ AssertUtils.ArgumentNotNull( indexer, "You cannot create a dynamic indexer for a null value." );
+
+ IDynamicIndexer dynamicIndexer = new SafeIndexer( indexer );
+ return dynamicIndexer;
+ }
+ }
+#else
///
/// Factory class for dynamic indexers.
///
@@ -354,7 +526,7 @@ namespace Spring.Reflection.Dynamic
{
private static readonly CreateIndexerCallback s_createCallback = new CreateIndexerCallback(CreateInternal);
- #region Create Method
+ #region Create Method
///
/// Creates dynamic indexer instance for the specified .
@@ -500,12 +672,8 @@ namespace Spring.Reflection.Dynamic
}
if (argumentType.IsValueType)
{
-#if NET_2_0
- il.Emit(OpCodes.Unbox_Any, argumentType);
-#else
il.Emit(OpCodes.Unbox, argumentType);
il.Emit(OpCodes.Ldobj, argumentType);
-#endif
}
else
{
@@ -513,6 +681,8 @@ namespace Spring.Reflection.Dynamic
}
}
- #endregion
+ #endregion
}
-}
+#endif
+
+} // namespace
\ No newline at end of file
diff --git a/src/Spring/Spring.Core/Reflection/Dynamic/DynamicMethod.cs b/src/Spring/Spring.Core/Reflection/Dynamic/DynamicMethod.cs
index 608dbba5..eb2d6757 100644
--- a/src/Spring/Spring.Core/Reflection/Dynamic/DynamicMethod.cs
+++ b/src/Spring/Spring.Core/Reflection/Dynamic/DynamicMethod.cs
@@ -49,7 +49,7 @@ namespace Spring.Reflection.Dynamic
///
/// A method return value.
///
- object Invoke(object target, object[] arguments);
+ object Invoke(object target, params object[] arguments);
}
#endregion
@@ -66,7 +66,71 @@ namespace Spring.Reflection.Dynamic
///
public class SafeMethod : IDynamicMethod
{
- private MethodInfo method;
+ private readonly MethodInfo methodInfo;
+
+ ///
+ /// Gets the class, that declares this method
+ ///
+ public Type DeclaringType
+ {
+ get { return methodInfo.DeclaringType; }
+ }
+
+#if NET_2_0
+ #region Generated Function Cache
+
+ private static readonly IDictionary methodCache = new Hashtable();
+
+ ///
+ /// Obtains cached property info or creates a new entry, if none is found.
+ ///
+ private static FunctionDelegate GetOrCreateDynamicMethod(MethodInfo methodInfo)
+ {
+ FunctionDelegate method = (FunctionDelegate)methodCache[methodInfo];
+ if (method == null)
+ {
+ method = DynamicReflectionManager.CreateMethod(methodInfo);
+ lock (methodCache)
+ {
+ methodCache[methodInfo] = method;
+ }
+ }
+ return method;
+ }
+
+ #endregion
+
+ private readonly FunctionDelegate method;
+
+ ///
+ /// Creates a new instance of the safe method wrapper.
+ ///
+ /// Method to wrap.
+ public SafeMethod(MethodInfo methodInfo)
+ {
+ AssertUtils.ArgumentNotNull(methodInfo, "You cannot create a dynamic method for a null value.");
+
+ this.methodInfo = methodInfo;
+ this.method = GetOrCreateDynamicMethod(methodInfo);
+ }
+
+ ///
+ /// Invokes dynamic method.
+ ///
+ ///
+ /// Target object to invoke method on.
+ ///
+ ///
+ /// Method arguments.
+ ///
+ ///
+ /// A method return value.
+ ///
+ public object Invoke(object target, object[] arguments)
+ {
+ return this.method(target, arguments);
+ }
+#else
private IDynamicMethod dynamicMethod;
private bool isOptimized = false;
@@ -76,7 +140,7 @@ namespace Spring.Reflection.Dynamic
/// Method to wrap.
public SafeMethod(MethodInfo method)
{
- this.method = method;
+ this.methodInfo = method;
if (method.IsPublic &&
ReflectionUtils.IsTypeVisible(method.DeclaringType, DynamicReflectionManager.ASSEMBLY_NAME))
{
@@ -85,14 +149,6 @@ namespace Spring.Reflection.Dynamic
}
}
- ///
- /// Gets the class, that declares this method
- ///
- public Type DeclaringType
- {
- get { return method.DeclaringType; }
- }
-
///
/// Invokes dynamic method.
///
@@ -123,12 +179,12 @@ namespace Spring.Reflection.Dynamic
throw;
}
isOptimized = false;
- return method.Invoke(target, arguments);
+ return methodInfo.Invoke(target, arguments);
}
}
else
{
- return method.Invoke(target, arguments);
+ return methodInfo.Invoke(target, arguments);
}
}
@@ -136,10 +192,32 @@ namespace Spring.Reflection.Dynamic
{
return e.TargetSite.DeclaringType.FullName.IndexOf(DynamicReflectionManager.ASSEMBLY_NAME) >= 0;
}
+#endif
}
#endregion
+#if NET_2_0
+ ///
+ /// Factory class for dynamic methods.
+ ///
+ /// Aleksandar Seovic
+ public class DynamicMethod : BaseDynamicMember
+ {
+ ///
+ /// Creates dynamic method instance for the specified .
+ ///
+ /// Method info to create dynamic method for.
+ /// Dynamic method for the specified .
+ public static IDynamicMethod Create(MethodInfo method)
+ {
+ AssertUtils.ArgumentNotNull(method, "You cannot create a dynamic method for a null value.");
+
+ IDynamicMethod dynamicMethod = new SafeMethod(method);
+ return dynamicMethod;
+ }
+ }
+#else
///
/// Factory class for dynamic methods.
///
@@ -187,104 +265,11 @@ namespace Spring.Reflection.Dynamic
invokeMethod.DefineParameter(2, ParameterAttributes.None, "args");
ILGenerator il = invokeMethod.GetILGenerator();
- bool isValueType = method.DeclaringType.IsValueType;
- bool isStatic = method.IsStatic;
-
- IDictionary outArgs = new Hashtable();
- ParameterInfo[] args = method.GetParameters();
- for (int i = 0; i < args.Length; i++)
- {
- if (IsOutputOrRefArgument(args[i]))
- {
- SetupOutputArgument(il, args[i], outArgs);
- }
- }
-
- if (!isStatic)
- {
- SetupTargetInstance(il, method.DeclaringType);
- }
-
- for (int i = 0; i < args.Length; i++)
- {
- SetupMethodArgument(il, args[i], outArgs);
- }
- InvokeMethod(il, isStatic, isValueType, method);
- for (int i = 0; i < args.Length; i++)
- {
- if (IsOutputOrRefArgument(args[i]))
- {
- ProcessOutputArgument(il, args[i], outArgs);
- }
- }
- ProcessReturnValue(il, method.ReturnType);
- il.Emit(OpCodes.Ret);
- }
-
- private static bool IsOutputOrRefArgument(ParameterInfo argInfo)
- {
- return argInfo.IsOut || argInfo.ParameterType.Name.EndsWith("&");
- }
-
- private static void SetupOutputArgument(ILGenerator il, ParameterInfo argInfo, IDictionary outArgs)
- {
- Type argType = argInfo.ParameterType.GetElementType();
-
- LocalBuilder lb = il.DeclareLocal(argType);
- if (!argInfo.IsOut)
- {
- PushArgumentValue(il, argType, argInfo.Position);
- il.Emit(OpCodes.Stloc, lb);
- }
- outArgs[argInfo.Position] = lb;
- }
-
- private static void ProcessOutputArgument(ILGenerator il, ParameterInfo argInfo, IDictionary outArgs)
- {
- Type argType = argInfo.ParameterType.GetElementType();
-
- il.Emit(OpCodes.Ldarg_2);
- il.Emit(OpCodes.Ldc_I4, argInfo.Position);
- il.Emit(OpCodes.Ldloc, (LocalBuilder)outArgs[argInfo.Position]);
- if (argType.IsValueType)
- {
- il.Emit(OpCodes.Box, argType);
- }
- il.Emit(OpCodes.Stelem_Ref);
- }
-
- private static void SetupMethodArgument(ILGenerator il, ParameterInfo argInfo, IDictionary outArgs)
- {
- if (IsOutputOrRefArgument(argInfo))
- {
- il.Emit(OpCodes.Ldloca_S, (LocalBuilder)outArgs[argInfo.Position]);
- }
- else
- {
- PushArgumentValue(il, argInfo.ParameterType, argInfo.Position);
- }
- }
-
- private static void PushArgumentValue(ILGenerator il, Type argumentType, int argumentPosition)
- {
- il.Emit(OpCodes.Ldarg_2);
- il.Emit(OpCodes.Ldc_I4, argumentPosition);
- il.Emit(OpCodes.Ldelem_Ref);
- if (argumentType.IsValueType)
- {
-#if NET_2_0
- il.Emit(OpCodes.Unbox_Any, argumentType);
-#else
- il.Emit(OpCodes.Unbox, argumentType);
- il.Emit(OpCodes.Ldobj, argumentType);
-#endif
- }
- else
- {
- il.Emit(OpCodes.Castclass, argumentType);
- }
+ DynamicReflectionManager.EmitInvokeMethod(il, method, true);
}
#endregion
}
+
+#endif
}
diff --git a/src/Spring/Spring.Core/Reflection/Dynamic/DynamicProperty.cs b/src/Spring/Spring.Core/Reflection/Dynamic/DynamicProperty.cs
index a7b04643..743597cf 100644
--- a/src/Spring/Spring.Core/Reflection/Dynamic/DynamicProperty.cs
+++ b/src/Spring/Spring.Core/Reflection/Dynamic/DynamicProperty.cs
@@ -60,6 +60,30 @@ namespace Spring.Reflection.Dynamic
/// A new property value.
///
void SetValue(object target, object value);
+
+ ///
+ /// Gets the value of the dynamic property for the specified target object.
+ ///
+ ///
+ /// Target object to get property value from.
+ ///
+ /// Optional index values for indexed properties. This value should be null reference for non-indexed properties.
+ ///
+ /// A property value.
+ ///
+ object GetValue(object target, params object[] index);
+
+ ///
+ /// Gets the value of the dynamic property for the specified target object.
+ ///
+ ///
+ /// Target object to set property value on.
+ ///
+ ///
+ /// A new property value.
+ ///
+ /// Optional index values for indexed properties. This value should be null reference for non-indexed properties.
+ void SetValue(object target, object value, params object[] index);
}
#endregion
@@ -91,10 +115,10 @@ namespace Spring.Reflection.Dynamic
///
private class DynamicPropertyCacheEntry
{
- public readonly GetterDelegate Getter;
- public readonly SetterDelegate Setter;
+ public readonly PropertyGetterDelegate Getter;
+ public readonly PropertySetterDelegate Setter;
- public DynamicPropertyCacheEntry(GetterDelegate getter, SetterDelegate setter)
+ public DynamicPropertyCacheEntry(PropertyGetterDelegate getter, PropertySetterDelegate setter)
{
Getter = getter;
Setter = setter;
@@ -120,8 +144,8 @@ namespace Spring.Reflection.Dynamic
#endregion
- private readonly GetterDelegate getter;
- private readonly SetterDelegate setter;
+ private readonly PropertyGetterDelegate getter;
+ private readonly PropertySetterDelegate setter;
///
/// Creates a new instance of the safe property wrapper.
@@ -151,6 +175,21 @@ namespace Spring.Reflection.Dynamic
return getter(target);
}
+ ///
+ /// Gets the value of the dynamic property for the specified target object.
+ ///
+ ///
+ /// Target object to get property value from.
+ ///
+ /// Optional index values for indexed properties. This value should be null reference for non-indexed properties.
+ ///
+ /// A property value.
+ ///
+ public object GetValue(object target, params object[] index)
+ {
+ return getter(target, index);
+ }
+
///
/// Gets the value of the dynamic property for the specified target object.
///
@@ -165,6 +204,21 @@ namespace Spring.Reflection.Dynamic
setter(target, value);
}
+ ///
+ /// Gets the value of the dynamic property for the specified target object.
+ ///
+ ///
+ /// Target object to set property value on.
+ ///
+ ///
+ /// A new property value.
+ ///
+ /// Optional index values for indexed properties. This value should be null reference for non-indexed properties.
+ public void SetValue(object target, object value, params object[] index)
+ {
+ setter(target, value, index);
+ }
+
#else
private readonly IDynamicProperty dynamicProperty;
private readonly bool isOptimizedGet = false;
@@ -239,8 +293,9 @@ namespace Spring.Reflection.Dynamic
{
dynamicProperty.SetValue(target, value);
}
- catch (InvalidCastException)
+ catch (InvalidCastException ex)
{
+ Log.Debug("Failed optimized set", ex);
isOptimizedSet = false;
propertyInfo.SetValue(target, value, null);
}
@@ -268,6 +323,64 @@ namespace Spring.Reflection.Dynamic
throw;
}
}
+
+ ///
+ /// Gets the value of the dynamic indexer for the specified target object.
+ ///
+ ///
+ /// Target object to get indexer value from.
+ ///
+ ///
+ /// Indexer arguments.
+ ///
+ ///
+ /// A indexer value.
+ ///
+ public object GetValue(object target, object[] index)
+ {
+ if (isOptimizedGet)
+ {
+ try
+ {
+ return dynamicProperty.GetValue(target, index);
+ }
+ catch (InvalidCastException)
+ {
+ isOptimizedSet = false;
+ }
+ }
+ return propertyInfo.GetValue(target, index);
+ }
+
+ ///
+ /// Sets the value of the dynamic indexer for the specified target object.
+ ///
+ ///
+ /// Target object to set indexer value on.
+ ///
+ ///
+ /// Indexer arguments.
+ ///
+ ///
+ /// A new indexer value.
+ ///
+ public void SetValue(object target, object value, object[] index)
+ {
+ if (isOptimizedSet)
+ {
+ try
+ {
+ dynamicProperty.SetValue(target, value, index);
+ return;
+ }
+ catch (InvalidCastException ex)
+ {
+ Log.Debug("Failed optimized set", ex);
+ isOptimizedSet = false;
+ }
+ }
+ propertyInfo.SetValue(target, value, index);
+ }
#endif
///
/// Internal PropertyInfo accessor.
@@ -364,7 +477,9 @@ namespace Spring.Reflection.Dynamic
tb.AddInterfaceImplementation(typeof(IDynamicProperty));
GenerateGetValue(tb, property);
+ GenerateGetIndexedValue(tb, property);
GenerateSetValue(tb, property);
+ GenerateSetIndexedValue(tb, property);
Type dynamicPropertyType = tb.CreateType();
ConstructorInfo ctor = dynamicPropertyType.GetConstructor(Type.EmptyTypes);
@@ -401,6 +516,41 @@ namespace Spring.Reflection.Dynamic
}
}
+ private static void GenerateGetIndexedValue(TypeBuilder tb, PropertyInfo indexer)
+ {
+ MethodBuilder getValueMethod =
+ tb.DefineMethod("GetValue", METHOD_ATTRIBUTES, typeof(object), new Type[] { typeof(object), typeof(object[]) });
+ getValueMethod.DefineParameter(1, ParameterAttributes.None, "target");
+ getValueMethod.DefineParameter(2, ParameterAttributes.None, "index");
+
+ ILGenerator il = getValueMethod.GetILGenerator();
+ if (indexer.CanRead)
+ {
+ MethodInfo getMethod = indexer.GetGetMethod();
+ bool isValueType = indexer.DeclaringType.IsValueType;
+ bool isStatic = getMethod.IsStatic;
+
+ if (!isStatic)
+ {
+ SetupTargetInstance(il, indexer.DeclaringType);
+ }
+
+ Type[] argTypes = ReflectionUtils.GetParameterTypes(getMethod);
+ for (int i = 0; i < argTypes.Length; i++)
+ {
+ SetupIndexerArgument(il, 2, argTypes[i], i, true);
+ }
+
+ InvokeMethod(il, isStatic, isValueType, getMethod);
+ ProcessReturnValue(il, indexer.PropertyType);
+ il.Emit(OpCodes.Ret);
+ }
+ else
+ {
+ ThrowInvalidOperationException(il, "Cannot get value of a non-readable indexer");
+ }
+ }
+
private static void GenerateSetValue(TypeBuilder tb, PropertyInfo property)
{
MethodBuilder setValueMethod =
@@ -440,6 +590,71 @@ namespace Spring.Reflection.Dynamic
}
}
+ private static void GenerateSetIndexedValue(TypeBuilder tb, PropertyInfo indexer)
+ {
+ MethodBuilder setValueMethod =
+ tb.DefineMethod("SetValue", METHOD_ATTRIBUTES, typeof(void),
+ new Type[] { typeof(object), typeof(object), typeof(object[]) });
+ setValueMethod.DefineParameter(1, ParameterAttributes.None, "target");
+ setValueMethod.DefineParameter(2, ParameterAttributes.None, "value");
+ setValueMethod.DefineParameter(3, ParameterAttributes.None, "index");
+
+ ILGenerator il = setValueMethod.GetILGenerator();
+ if (indexer.CanWrite)
+ {
+ bool isValueType = indexer.DeclaringType.IsValueType;
+ if (isValueType)
+ {
+ ThrowInvalidOperationException(il, "Cannot set indexer value on a value type due to boxing.");
+ }
+ else
+ {
+ MethodInfo setMethod = indexer.GetSetMethod();
+ bool isStatic = setMethod.IsStatic;
+
+ if (!isStatic)
+ {
+ SetupTargetInstance(il, indexer.DeclaringType);
+ }
+
+ Type[] argTypes = ReflectionUtils.GetParameterTypes(setMethod);
+ for (int i = 0; i < argTypes.Length - 1; i++)
+ {
+ SetupIndexerArgument(il, 3, argTypes[i], i, true);
+ }
+
+ SetupArgument(il, indexer.PropertyType, 2);
+ InvokeMethod(il, isStatic, isValueType, setMethod);
+ il.Emit(OpCodes.Ret);
+ }
+ }
+ else
+ {
+ ThrowInvalidOperationException(il, "Cannot set value of a read-only indexer");
+ }
+ }
+
+ private static OpCode[] LdArgOpCodes = { OpCodes.Ldarg_0, OpCodes.Ldarg_1, OpCodes.Ldarg_2, OpCodes.Ldarg_3 };
+
+ private static void SetupIndexerArgument(ILGenerator il, int indexArgumentPosition, Type argumentType, int argumentPosition, bool isObjectArray)
+ {
+ il.Emit(LdArgOpCodes[indexArgumentPosition]);
+ if (isObjectArray)
+ {
+ il.Emit(OpCodes.Ldc_I4, argumentPosition);
+ il.Emit(OpCodes.Ldelem_Ref);
+ }
+ if (argumentType.IsValueType)
+ {
+ il.Emit(OpCodes.Unbox, argumentType);
+ il.Emit(OpCodes.Ldobj, argumentType);
+ }
+ else
+ {
+ il.Emit(OpCodes.Castclass, argumentType);
+ }
+ }
+
#endregion
}
diff --git a/src/Spring/Spring.Core/Reflection/Dynamic/DynamicReflectionManager.cs b/src/Spring/Spring.Core/Reflection/Dynamic/DynamicReflectionManager.cs
index ea0426f9..c76ffeac 100644
--- a/src/Spring/Spring.Core/Reflection/Dynamic/DynamicReflectionManager.cs
+++ b/src/Spring/Spring.Core/Reflection/Dynamic/DynamicReflectionManager.cs
@@ -1,5 +1,5 @@
-#region License
-
+#region License
+
/*
* Copyright © 2002-2007 the original author or authors.
*
@@ -14,543 +14,817 @@
* 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.
- */
+ */
+
+#endregion
+
+#region Imports
+
+using System;
+using System.Collections;
+using System.Diagnostics;
+using System.Reflection;
+using System.Reflection.Emit;
+using Spring.Util;
+
+#if NET_2_0
+using NetDynamicMethod = System.Reflection.Emit.DynamicMethod;
+#endif
+
+#endregion
+
+namespace Spring.Reflection.Dynamic
+{
+ ///
+ /// Represents a Get method
+ ///
+ /// the target instance when calling an instance method
+ /// the value return by the Get method
+ public delegate object FieldGetterDelegate( object target );
+
+ ///
+ /// Represents a Set method
+ ///
+ /// the target instance when calling an instance method
+ /// the value to be set
+ public delegate void FieldSetterDelegate( object target, object value );
+
+ ///
+ /// Represents an Indexer Get method
+ ///
+ /// the target instance when calling an instance method
+ ///
+ /// the value return by the Get method
+ public delegate object PropertyGetterDelegate( object target, params object[] index );
+
+ ///
+ /// Represents a Set method
+ ///
+ /// the target instance when calling an instance method
+ /// the value to be set
+ ///
+ public delegate void PropertySetterDelegate( object target, object value, params object[] index );
+
+ ///
+ /// Represents a method
+ ///
+ /// the target instance when calling an instance method
+ /// arguments to be passed to the method
+ /// the value return by the method. null when calling a void method
+ public delegate object FunctionDelegate( object target, params object[] args );
+
+ ///
+ /// Represents a constructor
+ ///
+ /// arguments to be passed to the method
+ /// the new object instance
+ public delegate object ConstructorDelegate( params object[] args );
+
+ ///
+ /// Represents a callback method used to create an from a instance.
+ ///
+ internal delegate IDynamicProperty CreatePropertyCallback( PropertyInfo property );
+ ///
+ /// Represents a callback method used to create an from a instance.
+ ///
+ internal delegate IDynamicField CreateFieldCallback( FieldInfo property );
+ ///
+ /// Represents a callback method used to create an from a instance.
+ ///
+ internal delegate IDynamicMethod CreateMethodCallback( MethodInfo method );
+ ///
+ /// Represents a callback method used to create an from a instance.
+ ///
+ internal delegate IDynamicConstructor CreateConstructorCallback( ConstructorInfo constructor );
+ ///
+ /// Represents a callback method used to create an from a instance.
+ ///
+ internal delegate IDynamicIndexer CreateIndexerCallback( PropertyInfo indexer );
+
+ ///
+ /// Allows easy access to existing and creation of new dynamic relection members.
+ ///
+ /// Aleksandar Seovic
+ public sealed class DynamicReflectionManager
+ {
+ #region Obsolete Code
+
+
+ #region Fields
+
+ ///
+ /// The name of the assembly that defines reflection types created.
+ ///
+ public const string ASSEMBLY_NAME = "Spring.DynamicReflection";
+
+ ///
+ /// The attributes of the reflection type to generate.
+ ///
+ private const TypeAttributes TYPE_ATTRIBUTES = TypeAttributes.BeforeFieldInit | TypeAttributes.Public;
+
+ ///
+ /// Cache for dynamic property types.
+ ///
+ private readonly static IDictionary propertyCache = new Hashtable();
+
+ ///
+ /// Cache for dynamic field types.
+ ///
+ private readonly static IDictionary fieldCache = new Hashtable();
+
+ ///
+ /// Cache for dynamic indexer types.
+ ///
+ private readonly static IDictionary indexerCache = new Hashtable();
+
+ ///
+ /// Cache for dynamic method types.
+ ///
+ private readonly static IDictionary methodCache = new Hashtable();
+
+ ///
+ /// Cache for dynamic constructor types.
+ ///
+ private readonly static IDictionary constructorCache = new Hashtable();
+
+ #endregion
+
+ ///
+ /// Creates an appropriate type builder.
+ ///
+ ///
+ /// The base name to use for the reflection type name.
+ ///
+ /// The type builder to use.
+ internal static TypeBuilder CreateTypeBuilder( string name )
+ {
+ // Generates type name
+ string typeName = String.Format( "{0}.{1}_{2}",
+ ASSEMBLY_NAME, name, Guid.NewGuid().ToString( "N" ) );
+
+ ModuleBuilder module = DynamicCodeManager.GetModuleBuilder( ASSEMBLY_NAME );
+ return module.DefineType( typeName, TYPE_ATTRIBUTES );
+ }
+
+ ///
+ /// Returns dynamic property if one exists.
+ ///
+ /// Property to look up.
+ /// callback function that will be called to create the dynamic property
+ /// An for the given property info.
+ internal static IDynamicProperty GetDynamicProperty( PropertyInfo property, CreatePropertyCallback createCallback )
+ {
+ lock (propertyCache.SyncRoot)
+ {
+ IDynamicProperty dynamicProperty = (IDynamicProperty)propertyCache[property];
+ if (dynamicProperty == null)
+ {
+ dynamicProperty = createCallback( property );
+ propertyCache[property] = dynamicProperty;
+ }
+ return dynamicProperty;
+ }
+ }
+
+ ///
+ /// Returns dynamic field if one exists.
+ ///
+ /// Field to look up.
+ /// callback function that will be called to create the dynamic field
+ /// An for the given field info.
+ internal static IDynamicField GetDynamicField( FieldInfo field, CreateFieldCallback createCallback )
+ {
+ lock (fieldCache.SyncRoot)
+ {
+ IDynamicField dynamicField = (IDynamicField)fieldCache[field];
+ if (dynamicField == null)
+ {
+ dynamicField = createCallback( field );
+ fieldCache[field] = dynamicField;
+ }
+ return dynamicField;
+ }
+ }
+
+ ///
+ /// Returns dynamic indexer if one exists.
+ ///
+ /// Indexer to look up.
+ /// callback function that will be called to create the dynamic indexer
+ /// An for the given indexer.
+ internal static IDynamicIndexer GetDynamicIndexer( PropertyInfo indexer, CreateIndexerCallback createCallback )
+ {
+ lock (indexerCache.SyncRoot)
+ {
+ IDynamicIndexer dynamicIndexer = (IDynamicIndexer)indexerCache[indexer];
+ if (dynamicIndexer == null)
+ {
+ dynamicIndexer = createCallback( indexer );
+ indexerCache[indexer] = dynamicIndexer;
+ }
+ return dynamicIndexer;
+ }
+ }
+
+ ///
+ /// Returns dynamic method if one exists.
+ ///
+ /// Method to look up.
+ /// callback function that will be called to create the dynamic method
+ /// An for the given method.
+ internal static IDynamicMethod GetDynamicMethod( MethodInfo method, CreateMethodCallback createCallback )
+ {
+ lock (methodCache.SyncRoot)
+ {
+ IDynamicMethod dynamicMethod = (IDynamicMethod)methodCache[method];
+ if (dynamicMethod == null)
+ {
+ dynamicMethod = createCallback( method );
+ methodCache[method] = dynamicMethod;
+ }
+ return dynamicMethod;
+ }
+ }
+
+ ///
+ /// Returns dynamic constructor if one exists.
+ ///
+ /// Constructor to look up.
+ /// callback function that will be called to create the dynamic constructor
+ /// An for the given constructor.
+ internal static IDynamicConstructor GetDynamicConstructor( ConstructorInfo constructor, CreateConstructorCallback createCallback )
+ {
+ lock (constructorCache.SyncRoot)
+ {
+ IDynamicConstructor dynamicConstructor = (IDynamicConstructor)constructorCache[constructor];
+ if (dynamicConstructor == null)
+ {
+ dynamicConstructor = createCallback( constructor );
+ constructorCache[constructor] = dynamicConstructor;
+ }
+ return dynamicConstructor;
+ }
+ }
+
+ ///
+ /// Saves dynamically generated assembly to disk.
+ /// Can only be called in DEBUG mode, per ConditionalAttribute rules.
+ ///
+ [Conditional( "DEBUG_DYNAMIC" )]
+ public static void SaveAssembly()
+ {
+ DynamicCodeManager.SaveAssembly( ASSEMBLY_NAME );
+ }
+
+ #endregion
+
+#if NET_2_0
+ ///
+ /// Create a new Get method delegate for the specified field using
+ ///
+ /// the field to create the delegate for
+ /// a delegate that can be used to read the field
+ public static FieldGetterDelegate CreateFieldGetter( FieldInfo fieldInfo )
+ {
+ AssertUtils.ArgumentNotNull( fieldInfo, "You cannot create a delegate for a null value." );
+
+ System.Reflection.Emit.DynamicMethod dmGetter = new System.Reflection.Emit.DynamicMethod( "getter", typeof( object ), new Type[] { typeof( object ) }, fieldInfo.DeclaringType.Module, true );
+ ILGenerator il = dmGetter.GetILGenerator();
+ EmitFieldGetter( il, fieldInfo, false );
+ return (FieldGetterDelegate)dmGetter.CreateDelegate( typeof( FieldGetterDelegate ) );
+ }
+
+ ///
+ /// Create a new Set method delegate for the specified field using
+ ///
+ /// the field to create the delegate for
+ /// a delegate that can be used to read the field.
+ ///
+ /// If the field's returns true, the returned method
+ /// will throw an when called.
+ ///
+ public static FieldSetterDelegate CreateFieldSetter( FieldInfo fieldInfo )
+ {
+ AssertUtils.ArgumentNotNull( fieldInfo, "You cannot create a delegate for a null value." );
+
+ System.Reflection.Emit.DynamicMethod dmSetter = new System.Reflection.Emit.DynamicMethod( "setter", null, new Type[] { typeof( object ), typeof( object ) }, fieldInfo.DeclaringType.Module, true );
+ ILGenerator il = dmSetter.GetILGenerator();
+ EmitFieldSetter( il, fieldInfo, false );
+ return (FieldSetterDelegate)dmSetter.CreateDelegate( typeof( FieldSetterDelegate ) );
+ }
+
+ ///
+ /// Create a new Get method delegate for the specified property using
+ ///
+ /// the property to create the delegate for
+ /// a delegate that can be used to read the property.
+ ///
+ /// If the property's returns false, the returned method
+ /// will throw an when called.
+ ///
+ public static PropertyGetterDelegate CreatePropertyGetter( PropertyInfo propertyInfo )
+ {
+ AssertUtils.ArgumentNotNull( propertyInfo, "You cannot create a delegate for a null value." );
+
+ NetDynamicMethod dm = new NetDynamicMethod( string.Empty, typeof( object ), new Type[] { typeof( object ), typeof( object[] ) }, propertyInfo.DeclaringType.Module, true );
+ ILGenerator il = dm.GetILGenerator();
+ EmitPropertyGetter( il, propertyInfo, false );
+ return (PropertyGetterDelegate)dm.CreateDelegate( typeof( PropertyGetterDelegate ) );
+ }
+
+ ///
+ /// Create a new Set method delegate for the specified property using
+ ///
+ /// the property to create the delegate for
+ /// a delegate that can be used to write the property.
+ ///
+ /// If the property's returns false, the returned method
+ /// will throw an when called.
+ ///
+ public static PropertySetterDelegate CreatePropertySetter( PropertyInfo propertyInfo )
+ {
+ AssertUtils.ArgumentNotNull( propertyInfo, "You cannot create a delegate for a null value." );
+
+ NetDynamicMethod dm = new NetDynamicMethod( string.Empty, null, new Type[] { typeof( object ), typeof( object ), typeof( object[] ) }, propertyInfo.DeclaringType.Module, true );
+ ILGenerator il = dm.GetILGenerator();
+ EmitPropertySetter( il, propertyInfo, false );
+ return (PropertySetterDelegate)dm.CreateDelegate( typeof( PropertySetterDelegate ) );
+ }
+
+ ///
+ /// Create a new method delegate for the specified method using
+ ///
+ /// the method to create the delegate for
+ /// a delegate that can be used to invoke the method.
+ public static FunctionDelegate CreateMethod( MethodInfo methodInfo )
+ {
+ AssertUtils.ArgumentNotNull( methodInfo, "You cannot create a delegate for a null value." );
+
+ NetDynamicMethod dm = new NetDynamicMethod( string.Empty, typeof( object ), new Type[] { typeof( object ), typeof( object[] ) }, methodInfo.DeclaringType.Module, true );
+ ILGenerator il = dm.GetILGenerator();
+ EmitInvokeMethod( il, methodInfo, false );
+ return (FunctionDelegate)dm.CreateDelegate( typeof( FunctionDelegate ) );
+ }
+
+ ///
+ /// Creates a new delegate for the specified constructor.
+ ///
+ ///the constructor to create the delegate for
+ ///delegate that can be used to invoke the constructor.
+ public static ConstructorDelegate CreateConstructor(ConstructorInfo constructorInfo)
+ {
+ AssertUtils.ArgumentNotNull(constructorInfo, "You cannot create a dynamic constructor for a null value.");
+
+ System.Reflection.Emit.DynamicMethod dmGetter = new System.Reflection.Emit.DynamicMethod( string.Empty, typeof( object ), new Type[] { typeof( object[] ) }, constructorInfo.DeclaringType.Module, true );
+ ILGenerator il = dmGetter.GetILGenerator();
+ EmitInvokeConstructor( il, constructorInfo, false );
+ ConstructorDelegate ctor = (ConstructorDelegate)dmGetter.CreateDelegate( typeof( ConstructorDelegate ) );
+ return ctor;
+ }
+#endif
+
+ #region Shared Code Generation
+
+ private static void EmitFieldGetter( ILGenerator il, FieldInfo fieldInfo, bool isInstanceMethod )
+ {
+ if (fieldInfo.IsLiteral)
+ {
+ object value = fieldInfo.GetValue( null );
+ EmitConstant( il, value );
+ }
+ else if (fieldInfo.IsStatic)
+ {
+ il.Emit( OpCodes.Ldsfld, fieldInfo );
+ }
+ else
+ {
+ EmitTarget( il, fieldInfo.DeclaringType, isInstanceMethod );
+ il.Emit( OpCodes.Ldfld, fieldInfo );
+ }
+
+ if (fieldInfo.FieldType.IsValueType)
+ {
+ il.Emit( OpCodes.Box, fieldInfo.FieldType );
+ }
+ il.Emit( OpCodes.Ret );
+ }
+
+ internal static void EmitFieldSetter( ILGenerator il, FieldInfo fieldInfo, bool isInstanceMethod )
+ {
+ if (!fieldInfo.IsLiteral
+ && !fieldInfo.IsInitOnly
+ && !(fieldInfo.DeclaringType.IsValueType && !fieldInfo.IsStatic))
+ {
+ if (!fieldInfo.IsStatic)
+ {
+ EmitTarget( il, fieldInfo.DeclaringType, isInstanceMethod );
+ }
+ il.Emit( OpCodes.Ldarg_1 );
+ if (fieldInfo.FieldType.IsValueType)
+ {
+ EmitUnbox( il, fieldInfo.FieldType );
+ }
+ if (fieldInfo.IsStatic)
+ {
+ il.Emit( OpCodes.Stsfld, fieldInfo );
+ }
+ else
+ {
+ il.Emit( OpCodes.Stfld, fieldInfo );
+ }
+ il.Emit( OpCodes.Ret );
+ }
+ else
+ {
+ EmitThrowInvalidOperationException( il, string.Format( "Cannot write to read-only field '{0}.{1}'", fieldInfo.DeclaringType.FullName, fieldInfo.Name ) );
+ }
+ }
+
+ internal static void EmitPropertyGetter( ILGenerator il, PropertyInfo propertyInfo, bool isInstanceMethod )
+ {
+ if (propertyInfo.CanRead)
+ {
+ MethodInfo getMethod = propertyInfo.GetGetMethod( true );
+ EmitInvokeMethod( il, getMethod, isInstanceMethod );
+ }
+ else
+ {
+ EmitThrowInvalidOperationException( il, string.Format( "Cannot read from write-only property '{0}.{1}'", propertyInfo.DeclaringType.FullName, propertyInfo.Name ) );
+ }
+ }
+
+ internal static void EmitPropertySetter( ILGenerator il, PropertyInfo propertyInfo, bool isInstanceMethod )
+ {
+ MethodInfo method = propertyInfo.GetSetMethod( true );
+
+ if (propertyInfo.CanWrite
+ && !(propertyInfo.DeclaringType.IsValueType && !method.IsStatic))
+ {
+ // Note: last arg is property value!
+ // property set method signature:
+ // void set_MyOtherProperty( [indexArg1, indexArg2, ...], string value)
+
+ const int paramsArrayPosition = 2;
+ IDictionary outArgs = new Hashtable();
+ ParameterInfo[] args = propertyInfo.GetIndexParameters(); // get indexParameters here!
+ for (int i = 0; i < args.Length; i++)
+ {
+ SetupOutputArgument( il, paramsArrayPosition, args[i], outArgs );
+ }
+
+ // load target
+ if (!method.IsStatic)
+ {
+ EmitTarget( il, method.DeclaringType, isInstanceMethod );
+ }
+
+ // load indexer arguments
+ for (int i = 0; i < args.Length; i++)
+ {
+ SetupMethodArgument( il, paramsArrayPosition, args[i], outArgs );
+ }
+
+ // load value
+ il.Emit( OpCodes.Ldarg_1 );
+ if (propertyInfo.PropertyType.IsValueType)
+ {
+ EmitUnbox( il, propertyInfo.PropertyType );
+ }
+
+ // call setter
+ EmitCall( il, method );
+
+ for (int i = 0; i < args.Length; i++)
+ {
+ ProcessOutputArgument( il, paramsArrayPosition, args[i], outArgs );
+ }
+ il.Emit( OpCodes.Ret );
+ }
+ else
+ {
+ EmitThrowInvalidOperationException( il, string.Format( "Cannot write to read-only property '{0}.{1}'", propertyInfo.DeclaringType.FullName, propertyInfo.Name ) );
+ }
+ }
+
+ ///
+ /// Delegates a Method(object target, params object[] args) call to the actual underlying method.
+ ///
+ internal static void EmitInvokeMethod( ILGenerator il, MethodInfo method, bool isInstanceMethod )
+ {
+ int paramsArrayPosition = (isInstanceMethod) ? 2 : 1;
+ ParameterInfo[] args = method.GetParameters();
+ IDictionary outArgs = new Hashtable();
+ for (int i = 0; i < args.Length; i++)
+ {
+ SetupOutputArgument( il, paramsArrayPosition, args[i], outArgs );
+ }
+
+ if (!method.IsStatic)
+ {
+ EmitTarget( il, method.DeclaringType, isInstanceMethod );
+ }
+
+ for (int i = 0; i < args.Length; i++)
+ {
+ SetupMethodArgument( il, paramsArrayPosition, args[i], outArgs );
+ }
+
+ EmitCall( il, method );
+
+ for (int i = 0; i < args.Length; i++)
+ {
+ ProcessOutputArgument( il, paramsArrayPosition, args[i], outArgs );
+ }
+
+ EmitMethodReturn( il, method.ReturnType );
+ }
+
+ internal static void EmitInvokeConstructor(ILGenerator il, ConstructorInfo constructor, bool isInstanceMethod)
+ {
+ int paramsArrayPosition = (isInstanceMethod) ? 1 : 0;
+ ParameterInfo[] args = constructor.GetParameters();
-#endregion
+ IDictionary outArgs = new Hashtable();
+ for (int i = 0; i < args.Length; i++)
+ {
+ SetupOutputArgument( il, paramsArrayPosition, args[i], outArgs );
+ }
-#region Imports
+ for (int i = 0; i < args.Length; i++)
+ {
+ SetupMethodArgument(il, paramsArrayPosition, args[i], null);
+ }
+
+ il.Emit(OpCodes.Newobj, constructor);
-using System;
-using System.Collections;
-using System.Diagnostics;
-using System.Reflection;
-using System.Reflection.Emit;
-using Spring.Util;
+ for (int i = 0; i < args.Length; i++)
+ {
+ ProcessOutputArgument( il, paramsArrayPosition, args[i], outArgs );
+ }
-#if NET_2_0
-using NetDynamicMethod = System.Reflection.Emit.DynamicMethod;
-#endif
-
-#endregion
-
-namespace Spring.Reflection.Dynamic
-{
- ///
- /// Represents a Get method
- ///
- /// the target instance when calling an instance method
- /// the value return by the Get method
- public delegate object GetterDelegate(object target);
-
- ///
- /// Represents a Set method
- ///
- /// the target instance when calling an instance method
- /// the value to be set
- public delegate void SetterDelegate(object target, object value);
-
- ///
- /// Represents a method
- ///
- /// the target instance when calling an instance method
- /// arguments to be passed to the method
- /// the value return by the method. null when calling a void method
- public delegate object FunctionDelegate(object target, params object[] args);
-
- ///
- /// Represents a callback method used to create an from a instance.
- ///
- internal delegate IDynamicProperty CreatePropertyCallback(PropertyInfo property);
- ///
- /// Represents a callback method used to create an from a instance.
- ///
- internal delegate IDynamicField CreateFieldCallback(FieldInfo property);
- ///
- /// Represents a callback method used to create an from a instance.
- ///
- internal delegate IDynamicMethod CreateMethodCallback(MethodInfo method);
- ///
- /// Represents a callback method used to create an from a instance.
- ///
- internal delegate IDynamicConstructor CreateConstructorCallback(ConstructorInfo constructor);
- ///
- /// Represents a callback method used to create an from a instance.
- ///
- internal delegate IDynamicIndexer CreateIndexerCallback(PropertyInfo indexer);
-
- ///
- /// Allows easy access to existing and creation of new dynamic relection members.
- ///
- /// Aleksandar Seovic
- public sealed class DynamicReflectionManager
- {
- #region Fields
-
- ///
- /// The name of the assembly that defines reflection types created.
- ///
- public const string ASSEMBLY_NAME = "Spring.DynamicReflection";
-
- ///
- /// The attributes of the reflection type to generate.
- ///
- private const TypeAttributes TYPE_ATTRIBUTES = TypeAttributes.BeforeFieldInit | TypeAttributes.Public;
-
- ///
- /// Cache for dynamic property types.
- ///
- private readonly static IDictionary propertyCache = new Hashtable();
-
- ///
- /// Cache for dynamic field types.
- ///
- private readonly static IDictionary fieldCache = new Hashtable();
-
- ///
- /// Cache for dynamic indexer types.
- ///
- private readonly static IDictionary indexerCache = new Hashtable();
-
- ///
- /// Cache for dynamic method types.
- ///
- private readonly static IDictionary methodCache = new Hashtable();
-
- ///
- /// Cache for dynamic constructor types.
- ///
- private readonly static IDictionary constructorCache = new Hashtable();
-
- #endregion
-
- #region Public Methods
-
- ///
- /// Creates an appropriate type builder.
- ///
- ///
- /// The base name to use for the reflection type name.
- ///
- /// The type builder to use.
- internal static TypeBuilder CreateTypeBuilder(string name)
- {
- // Generates type name
- string typeName = String.Format("{0}.{1}_{2}",
- ASSEMBLY_NAME, name, Guid.NewGuid().ToString("N"));
-
- ModuleBuilder module = DynamicCodeManager.GetModuleBuilder(ASSEMBLY_NAME);
- return module.DefineType(typeName, TYPE_ATTRIBUTES);
+ EmitMethodReturn(il, constructor.DeclaringType);
}
-
- ///
- /// Returns dynamic property if one exists.
- ///
- /// Property to look up.
- /// callback function that will be called to create the dynamic property
- /// An for the given property info.
- internal static IDynamicProperty GetDynamicProperty(PropertyInfo property, CreatePropertyCallback createCallback)
- {
- lock (propertyCache.SyncRoot)
- {
- IDynamicProperty dynamicProperty = (IDynamicProperty)propertyCache[property];
- if (dynamicProperty == null)
- {
- dynamicProperty = createCallback(property);
- propertyCache[property] = dynamicProperty;
- }
- return dynamicProperty;
- }
- }
-
- ///
- /// Returns dynamic field if one exists.
- ///
- /// Field to look up.
- /// callback function that will be called to create the dynamic field
- /// An for the given field info.
- internal static IDynamicField GetDynamicField(FieldInfo field, CreateFieldCallback createCallback)
- {
- lock (fieldCache.SyncRoot)
- {
- IDynamicField dynamicField = (IDynamicField)fieldCache[field];
- if (dynamicField == null)
- {
- dynamicField = createCallback(field);
- fieldCache[field] = dynamicField;
- }
- return dynamicField;
- }
- }
-
- ///
- /// Returns dynamic indexer if one exists.
- ///
- /// Indexer to look up.
- /// callback function that will be called to create the dynamic indexer
- /// An for the given indexer.
- internal static IDynamicIndexer GetDynamicIndexer(PropertyInfo indexer, CreateIndexerCallback createCallback)
- {
- lock (indexerCache.SyncRoot)
- {
- IDynamicIndexer dynamicIndexer = (IDynamicIndexer)indexerCache[indexer];
- if (dynamicIndexer == null)
- {
- dynamicIndexer = createCallback(indexer);
- indexerCache[indexer] = dynamicIndexer;
- }
- return dynamicIndexer;
- }
- }
-
- ///
- /// Returns dynamic method if one exists.
- ///
- /// Method to look up.
- /// callback function that will be called to create the dynamic method
- /// An for the given method.
- internal static IDynamicMethod GetDynamicMethod(MethodInfo method, CreateMethodCallback createCallback)
- {
- lock (methodCache.SyncRoot)
- {
- IDynamicMethod dynamicMethod = (IDynamicMethod)methodCache[method];
- if (dynamicMethod == null)
- {
- dynamicMethod = createCallback(method);
- methodCache[method] = dynamicMethod;
- }
- return dynamicMethod;
- }
- }
-
- ///
- /// Returns dynamic constructor if one exists.
- ///
- /// Constructor to look up.
- /// callback function that will be called to create the dynamic constructor
- /// An for the given constructor.
- internal static IDynamicConstructor GetDynamicConstructor(ConstructorInfo constructor, CreateConstructorCallback createCallback)
- {
- lock (constructorCache.SyncRoot)
- {
- IDynamicConstructor dynamicConstructor = (IDynamicConstructor)constructorCache[constructor];
- if (dynamicConstructor == null)
- {
- dynamicConstructor = createCallback(constructor);
- constructorCache[constructor] = dynamicConstructor;
- }
- return dynamicConstructor;
- }
- }
-
- ///
- /// Saves dynamically generated assembly to disk.
- /// Can only be called in DEBUG mode, per ConditionalAttribute rules.
- ///
- [Conditional("DEBUG_DYNAMIC")]
- public static void SaveAssembly()
- {
- DynamicCodeManager.SaveAssembly(ASSEMBLY_NAME);
- }
-
- #endregion
-
-#if NET_2_0
- private static readonly ConstructorInfo NewInvalidOperationException =
- typeof(InvalidOperationException).GetConstructor(new Type[] { typeof(string) });
-
- ///
- /// Create a new Get method delegate for the specified field using
- ///
- /// the field to create the delegate for
- /// a delegate that can be used to read the field
- public static GetterDelegate CreateFieldGetter(FieldInfo fieldInfo)
- {
- AssertUtils.ArgumentNotNull(fieldInfo, "You cannot create a delegate for a null value.");
-
- System.Reflection.Emit.DynamicMethod dmGetter = new System.Reflection.Emit.DynamicMethod("getter", typeof(object), new Type[] { typeof(object) }, fieldInfo.DeclaringType.Module, true);
- ILGenerator il = dmGetter.GetILGenerator();
- if (fieldInfo.IsLiteral)
- {
- object value = fieldInfo.GetValue(null);
- EmitConstant(il, value);
- }
- else if (fieldInfo.IsStatic)
- {
- il.Emit(OpCodes.Ldsfld, fieldInfo);
- }
- else
- {
- EmitTarget(il, fieldInfo.DeclaringType);
- il.Emit(OpCodes.Ldfld, fieldInfo);
- }
-
- if (fieldInfo.FieldType.IsValueType)
- {
- il.Emit(OpCodes.Box, fieldInfo.FieldType);
- }
- il.Emit(OpCodes.Ret);
- return (GetterDelegate)dmGetter.CreateDelegate(typeof(GetterDelegate));
- }
-
- ///
- /// Create a new Set method delegate for the specified field using
- ///
- /// the field to create the delegate for
- /// a delegate that can be used to read the field.
- ///
- /// If the field's returns true, the returned method
- /// will throw an when called.
- ///
- public static SetterDelegate CreateFieldSetter(FieldInfo fieldInfo)
- {
- AssertUtils.ArgumentNotNull(fieldInfo, "You cannot create a delegate for a null value.");
-
- System.Reflection.Emit.DynamicMethod dmSetter = new System.Reflection.Emit.DynamicMethod("setter", null, new Type[] { typeof(object), typeof(object) }, fieldInfo.DeclaringType.Module, true);
- ILGenerator il = dmSetter.GetILGenerator();
-
- if (!fieldInfo.IsLiteral
- && !fieldInfo.IsInitOnly
- && !(fieldInfo.DeclaringType.IsValueType && !fieldInfo.IsStatic))
- {
- if (!fieldInfo.IsStatic)
- {
- EmitTarget(il, fieldInfo.DeclaringType);
- }
- il.Emit(OpCodes.Ldarg_1);
- if (fieldInfo.FieldType.IsValueType)
- {
- il.Emit(OpCodes.Unbox_Any, fieldInfo.FieldType);
- }
- if (fieldInfo.IsStatic)
- {
- il.Emit(OpCodes.Stsfld, fieldInfo);
- }
- else
- {
- il.Emit(OpCodes.Stfld, fieldInfo);
- }
- il.Emit(OpCodes.Ret);
- }
- else
- {
- EmitThrowInvalidOperationException(il, string.Format("Cannot write to constant field '{0}.{1}'", fieldInfo.DeclaringType.FullName, fieldInfo.Name));
- }
- return (SetterDelegate)dmSetter.CreateDelegate(typeof(SetterDelegate));
- }
-
- ///
- /// Create a new Get method delegate for the specified property using
- ///
- /// the property to create the delegate for
- /// a delegate that can be used to read the property.
- ///
- /// If the property's returns false, the returned method
- /// will throw an when called.
- ///
- public static GetterDelegate CreatePropertyGetter(PropertyInfo propertyInfo)
- {
- AssertUtils.ArgumentNotNull(propertyInfo, "You cannot create a delegate for a null value.");
-
- NetDynamicMethod dm = new NetDynamicMethod(string.Empty, typeof(object), new Type[] { typeof(object) }, propertyInfo.DeclaringType.Module, true);
- ILGenerator il = dm.GetILGenerator();
-
- if (propertyInfo.CanRead)
- {
- MethodInfo method = propertyInfo.GetGetMethod(true);
- if (!method.IsStatic)
- {
- EmitTarget(il, method.DeclaringType);
- }
- EmitCall(il, method);
- if (propertyInfo.PropertyType.IsValueType)
- {
- il.Emit(OpCodes.Box, propertyInfo.PropertyType);
- }
- il.Emit(OpCodes.Ret);
- }
- else
- {
- EmitThrowInvalidOperationException(il, string.Format("Cannot read from write-only property '{0}.{1}'", propertyInfo.DeclaringType.FullName, propertyInfo.Name));
- }
- return (GetterDelegate)dm.CreateDelegate(typeof(GetterDelegate));
- }
-
- ///
- /// Create a new Set method delegate for the specified property using
- ///
- /// the property to create the delegate for
- /// a delegate that can be used to write the property.
- ///
- /// If the property's returns false, the returned method
- /// will throw an when called.
- ///
- public static SetterDelegate CreatePropertySetter(PropertyInfo propertyInfo)
- {
- AssertUtils.ArgumentNotNull(propertyInfo, "You cannot create a delegate for a null value.");
-
- NetDynamicMethod dm = new NetDynamicMethod(string.Empty, null, new Type[] { typeof(object), typeof(object) }, propertyInfo.DeclaringType.Module, true);
- ILGenerator il = dm.GetILGenerator();
-
- if (propertyInfo.CanWrite
- && !(propertyInfo.DeclaringType.IsValueType && !propertyInfo.GetSetMethod(true).IsStatic))
- {
- MethodInfo method = propertyInfo.GetSetMethod(true);
- if (!method.IsStatic)
- {
- EmitTarget(il, method.DeclaringType);
- }
-
- il.Emit(OpCodes.Ldarg_1);
- if (propertyInfo.PropertyType.IsValueType)
- {
- il.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType);
- }
- EmitCall(il, method);
- il.Emit(OpCodes.Ret);
- }
- else
- {
- EmitThrowInvalidOperationException(il, string.Format("Cannot write to read-only property '{0}.{1}'", propertyInfo.DeclaringType.FullName, propertyInfo.Name));
- }
-
- return (SetterDelegate)dm.CreateDelegate(typeof(SetterDelegate));
- }
-
- ///
- /// Create a new method delegate for the specified method using
- ///
- /// the method to create the delegate for
- /// a delegate that can be used to invoke the method.
- private static FunctionDelegate CreateFunctionDelegate(MethodInfo method)
- {
- NetDynamicMethod dm = new NetDynamicMethod(string.Empty, typeof(object), new Type[] { typeof(object), typeof(object[]) }, method.DeclaringType.Module, true);
- ILGenerator il = dm.GetILGenerator();
- ParameterInfo[] parameters = method.GetParameters();
- for (int i = 0; i < parameters.Length; i++)
- {
- ParameterInfo p = parameters[i];
- il.Emit(OpCodes.Ldarg_1);
- il.Emit(OpCodes.Ldc_I4, i);
- il.Emit(OpCodes.Ldelem_Ref);
- if (p.ParameterType.IsValueType)
- {
- il.Emit(OpCodes.Unbox_Any, p.ParameterType);
- }
- }
-
- if (!method.IsStatic)
- {
- EmitTarget(il, method.DeclaringType);
- }
- EmitCall(il, method);
-
- if (method.ReturnType == typeof(void))
- {
- il.Emit(OpCodes.Ldnull);
- }
- il.Emit(OpCodes.Ret);
- return (FunctionDelegate)dm.CreateDelegate(typeof(FunctionDelegate));
- }
-
- private static void EmitTarget(ILGenerator il, Type targetType)
- {
- il.Emit(OpCodes.Ldarg_0);
- if (targetType.IsValueType)
- {
- LocalBuilder local = il.DeclareLocal(targetType);
- il.Emit(OpCodes.Unbox_Any, targetType);
- il.Emit(OpCodes.Stloc_0);
- il.Emit(OpCodes.Ldloca_S, 0);
- }
- }
-
- private static void EmitCall(ILGenerator il, MethodInfo method)
- {
- il.Emit((method.IsVirtual) ? OpCodes.Callvirt : OpCodes.Call, method);
- }
-
- private static void EmitConstant(ILGenerator il, object value)
- {
- if (value is String)
- {
- il.Emit(OpCodes.Ldstr, (string)value);
- return;
- }
-
- if (value is bool)
- {
- if ((bool)value)
- {
- il.Emit(OpCodes.Ldc_I4_1);
- }
- else
- {
- il.Emit(OpCodes.Ldc_I4_0);
- }
- return;
- }
-
- if (value is Char)
- {
- il.Emit(OpCodes.Ldc_I4, (Char)value);
- il.Emit(OpCodes.Conv_I2);
- return;
- }
-
- if (value is byte)
- {
- il.Emit(OpCodes.Ldc_I4, (byte)value);
- il.Emit(OpCodes.Conv_I1);
- }
- else if (value is Int16)
- {
- il.Emit(OpCodes.Ldc_I4, (Int16)value);
- il.Emit(OpCodes.Conv_I2);
- }
- else if (value is Int32)
- {
- il.Emit(OpCodes.Ldc_I4, (Int32)value);
- }
- else if (value is Int64)
- {
- il.Emit(OpCodes.Ldc_I8, (Int64)value);
- }
- else if (value is UInt16)
- {
- il.Emit(OpCodes.Ldc_I4, (UInt16)value);
- il.Emit(OpCodes.Conv_U2);
- }
- else if (value is UInt32)
- {
- il.Emit(OpCodes.Ldc_I4, (UInt32)value);
- il.Emit(OpCodes.Conv_U4);
- }
- else if (value is UInt64)
- {
- il.Emit(OpCodes.Ldc_I8, (UInt64)value);
- il.Emit(OpCodes.Conv_U8);
- }
- else if (value is Single)
- {
- il.Emit(OpCodes.Ldc_R4, (Single)value);
- }
- else if (value is Double)
- {
- il.Emit(OpCodes.Ldc_R8, (Double)value);
- }
- }
-
- ///
- /// Generates code that throws .
- ///
- /// IL generator to use.
- /// Error message to use.
- private static void EmitThrowInvalidOperationException(ILGenerator il, string message)
- {
- il.Emit(OpCodes.Ldstr, message);
- il.Emit(OpCodes.Newobj, NewInvalidOperationException);
- il.Emit(OpCodes.Throw);
- }
-#endif
- }
+
+ #endregion
+
+ private static OpCode[] LdArgOpCodes = { OpCodes.Ldarg_0, OpCodes.Ldarg_1, OpCodes.Ldarg_2 };
+
+ private static void SetupOutputArgument( ILGenerator il, int paramsArrayPosition, ParameterInfo argInfo, IDictionary outArgs )
+ {
+ if (!IsOutputOrRefArgument( argInfo ))
+ return;
+
+ Type argType = argInfo.ParameterType.GetElementType();
+
+ LocalBuilder lb = il.DeclareLocal( argType );
+ if (!argInfo.IsOut)
+ {
+ PushParamsArgumentValue( il, paramsArrayPosition, argType, argInfo.Position );
+ il.Emit( OpCodes.Stloc, lb );
+ }
+ outArgs[argInfo.Position] = lb;
+ }
+
+ private static bool IsOutputOrRefArgument( ParameterInfo argInfo )
+ {
+ return argInfo.IsOut || argInfo.ParameterType.Name.EndsWith( "&" );
+ }
+
+ private static void ProcessOutputArgument( ILGenerator il, int paramsArrayPosition, ParameterInfo argInfo, IDictionary outArgs )
+ {
+ if (!IsOutputOrRefArgument( argInfo ))
+ return;
+
+ Type argType = argInfo.ParameterType.GetElementType();
+
+ il.Emit( LdArgOpCodes[paramsArrayPosition] );
+ il.Emit( OpCodes.Ldc_I4, argInfo.Position );
+ il.Emit( OpCodes.Ldloc, (LocalBuilder)outArgs[argInfo.Position] );
+ if (argType.IsValueType)
+ {
+ il.Emit( OpCodes.Box, argType );
+ }
+ il.Emit( OpCodes.Stelem_Ref );
+ }
+
+ private static void SetupMethodArgument( ILGenerator il, int paramsArrayPosition, ParameterInfo argInfo, IDictionary outArgs )
+ {
+ if ( IsOutputOrRefArgument( argInfo ))
+ {
+ il.Emit( OpCodes.Ldloca_S, (LocalBuilder)outArgs[argInfo.Position] );
+ }
+ else
+ {
+ PushParamsArgumentValue( il, paramsArrayPosition, argInfo.ParameterType, argInfo.Position );
+ }
+ }
+
+ private static void PushParamsArgumentValue( ILGenerator il, int paramsArrayPosition, Type argumentType, int argumentPosition )
+ {
+ il.Emit( LdArgOpCodes[paramsArrayPosition] );
+ il.Emit( OpCodes.Ldc_I4, argumentPosition );
+ il.Emit( OpCodes.Ldelem_Ref );
+ if (argumentType.IsValueType)
+ {
+ // call ConvertArgumentIfNecessary() to convert e.g. int32 to double if necessary
+ il.Emit( OpCodes.Ldtoken, argumentType );
+ EmitCall( il, FnGetTypeFromHandle );
+ il.Emit( OpCodes.Ldc_I4, argumentPosition );
+ EmitCall( il, FnConvertArgumentIfNecessary );
+ EmitUnbox( il, argumentType );
+ }
+ else
+ {
+ il.Emit( OpCodes.Castclass, argumentType );
+ }
+ }
+
+ private static void EmitUnbox( ILGenerator il, Type argumentType )
+ {
+#if NET_2_0
+ il.Emit( OpCodes.Unbox_Any, argumentType );
+#else
+ il.Emit(OpCodes.Unbox, argumentType);
+ il.Emit(OpCodes.Ldobj, argumentType);
+#endif
+ }
+
+ ///
+ /// Generates code to process return value if necessary.
+ ///
+ /// IL generator to use.
+ /// Type of the return value.
+ private static void EmitMethodReturn( ILGenerator il, Type returnValueType )
+ {
+ if (returnValueType == typeof( void ))
+ {
+ il.Emit( OpCodes.Ldnull );
+ }
+ else if (returnValueType.IsValueType)
+ {
+ il.Emit( OpCodes.Box, returnValueType );
+ }
+ il.Emit( OpCodes.Ret );
+ }
+
+ private delegate Type GetTypeFromHandleDelegate( RuntimeTypeHandle handle );
+ private static readonly MethodInfo FnGetTypeFromHandle = new GetTypeFromHandleDelegate( Type.GetTypeFromHandle ).Method;
+ private delegate object ChangeTypeDelegate( object value, Type targetType, int argIndex );
+ private static readonly MethodInfo FnConvertArgumentIfNecessary = new ChangeTypeDelegate( ConvertValueTypeArgumentIfNecessary ).Method;
+
+ ///
+ /// Converts to an instance of if necessary to
+ /// e.g. avoid e.g. double/int cast exceptions.
+ ///
+ ///
+ ///
+ /// This method mimics the behavior of the compiler that
+ /// automatically performs casts like int to double in "Math.Sqrt(4)".
+ /// See about implicit, widening type conversions on MSDN - Type Conversion Tables
+ ///
+ ///
+ /// Note: is expected to be a value type!
+ ///
+ ///
+ public static object ConvertValueTypeArgumentIfNecessary( object value, Type targetType, int argIndex )
+ {
+ // targetType is guaranteed to be a ValueType!
+ if (value == null)
+ {
+ throw new InvalidCastException( string.Format( "Cannot convert NULL at position {0} to argument type {1}", argIndex, targetType.FullName ) );
+ }
+
+ Type valueType = value.GetType();
+
+ // no conversion necessary?
+ if (valueType == targetType)
+ {
+ return value;
+ }
+
+ if (!valueType.IsValueType)
+ {
+ // we're facing a reftype/valuetype mix that never can convert
+ throw new InvalidCastException( string.Format( "Cannot convert value '{0}' of type {1} at position {2} to argument type {3}", value, valueType.FullName, argIndex, targetType.FullName ) );
+ }
+
+ // we're dealing only with ValueType's now - try to convert them
+ try
+ {
+ // TODO: allow widening conversions only
+ return Convert.ChangeType( value, targetType );
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidCastException( string.Format( "Cannot convert value '{0}' of type {1} at position {2} to argument type {3}", value, valueType.FullName, argIndex, targetType.FullName ), ex );
+ }
+ }
+
+ private static void EmitTarget( ILGenerator il, Type targetType, bool isInstanceMethod )
+ {
+ il.Emit( (isInstanceMethod) ? OpCodes.Ldarg_1 : OpCodes.Ldarg_0 );
+ if (targetType.IsValueType)
+ {
+ LocalBuilder local = il.DeclareLocal( targetType );
+ EmitUnbox( il, targetType );
+ il.Emit( OpCodes.Stloc_0 );
+ il.Emit( OpCodes.Ldloca_S, 0 );
+ }
+ else
+ {
+ il.Emit( OpCodes.Castclass, targetType );
+ }
+ }
+
+ private static void EmitCall( ILGenerator il, MethodInfo method )
+ {
+ il.EmitCall( (method.IsVirtual) ? OpCodes.Callvirt : OpCodes.Call, method, null );
+ }
+
+ private static void EmitConstant( ILGenerator il, object value )
+ {
+ if (value is String)
+ {
+ il.Emit( OpCodes.Ldstr, (string)value );
+ return;
+ }
+
+ if (value is bool)
+ {
+ if ((bool)value)
+ {
+ il.Emit( OpCodes.Ldc_I4_1 );
+ }
+ else
+ {
+ il.Emit( OpCodes.Ldc_I4_0 );
+ }
+ return;
+ }
+
+ if (value is Char)
+ {
+ il.Emit( OpCodes.Ldc_I4, (Char)value );
+ il.Emit( OpCodes.Conv_I2 );
+ return;
+ }
+
+ if (value is byte)
+ {
+ il.Emit( OpCodes.Ldc_I4, (byte)value );
+ il.Emit( OpCodes.Conv_I1 );
+ }
+ else if (value is Int16)
+ {
+ il.Emit( OpCodes.Ldc_I4, (Int16)value );
+ il.Emit( OpCodes.Conv_I2 );
+ }
+ else if (value is Int32)
+ {
+ il.Emit( OpCodes.Ldc_I4, (Int32)value );
+ }
+ else if (value is Int64)
+ {
+ il.Emit( OpCodes.Ldc_I8, (Int64)value );
+ }
+ else if (value is UInt16)
+ {
+ il.Emit( OpCodes.Ldc_I4, (UInt16)value );
+ il.Emit( OpCodes.Conv_U2 );
+ }
+ else if (value is UInt32)
+ {
+ il.Emit( OpCodes.Ldc_I4, (UInt32)value );
+ il.Emit( OpCodes.Conv_U4 );
+ }
+ else if (value is UInt64)
+ {
+ il.Emit( OpCodes.Ldc_I8, (UInt64)value );
+ il.Emit( OpCodes.Conv_U8 );
+ }
+ else if (value is Single)
+ {
+ il.Emit( OpCodes.Ldc_R4, (Single)value );
+ }
+ else if (value is Double)
+ {
+ il.Emit( OpCodes.Ldc_R8, (Double)value );
+ }
+ }
+
+ private static readonly ConstructorInfo NewInvalidOperationException =
+ typeof( InvalidOperationException ).GetConstructor( new Type[] { typeof( string ) } );
+
+ ///
+ /// Generates code that throws .
+ ///
+ /// IL generator to use.
+ /// Error message to use.
+ private static void EmitThrowInvalidOperationException( ILGenerator il, string message )
+ {
+ il.Emit( OpCodes.Ldstr, message );
+ il.Emit( OpCodes.Newobj, NewInvalidOperationException );
+ il.Emit( OpCodes.Throw );
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Web/Spring.Web.2003.csproj b/src/Spring/Spring.Web/Spring.Web.2003.csproj
index be8b6f6b..288baa03 100644
--- a/src/Spring/Spring.Web/Spring.Web.2003.csproj
+++ b/src/Spring/Spring.Web/Spring.Web.2003.csproj
@@ -260,16 +260,6 @@
SubType = "Code"
BuildAction = "Compile"
/>
-
-
+
+
+
+
+
@@ -88,4 +90,6 @@ namespace Spring.Web.Support
return null;
}
}
-}
\ No newline at end of file
+}
+
+#endif
\ No newline at end of file
diff --git a/test/Spring/Spring.Core.Tests/Core/TypeResolution/TypeAssemblyHolderTests.cs b/test/Spring/Spring.Core.Tests/Core/TypeResolution/TypeAssemblyHolderTests.cs
index 85054f43..c8bc66e8 100644
--- a/test/Spring/Spring.Core.Tests/Core/TypeResolution/TypeAssemblyHolderTests.cs
+++ b/test/Spring/Spring.Core.Tests/Core/TypeResolution/TypeAssemblyHolderTests.cs
@@ -21,10 +21,13 @@
#region Imports
using System;
-using System.Collections.Generic;
using NUnit.Framework;
using Spring.Objects;
+#if NET_2_0
+using System.Collections.Generic;
+#endif
+
#endregion
namespace Spring.Core.TypeResolution
@@ -39,10 +42,6 @@ namespace Spring.Core.TypeResolution
[Test]
public void CanTakeQualifiedType()
{
- string tn = typeof(int[]).AssemblyQualifiedName;
- tn = typeof(TestGenericObject[]).AssemblyQualifiedName;
- tn = typeof(List).AssemblyQualifiedName;
-
Type testType = typeof(TestObject);
TypeAssemblyHolder tah = new TypeAssemblyHolder(testType.AssemblyQualifiedName);
Assert.IsTrue(tah.IsAssemblyQualified);
diff --git a/test/Spring/Spring.Core.Tests/Reflection/Dynamic/BasePropertyTests.cs b/test/Spring/Spring.Core.Tests/Reflection/Dynamic/BasePropertyTests.cs
index 87d2328c..31238a25 100644
--- a/test/Spring/Spring.Core.Tests/Reflection/Dynamic/BasePropertyTests.cs
+++ b/test/Spring/Spring.Core.Tests/Reflection/Dynamic/BasePropertyTests.cs
@@ -1,6 +1,9 @@
using System;
+using System.CodeDom.Compiler;
using System.Diagnostics;
+using System.IO;
using System.Reflection;
+using System.Text;
using NUnit.Framework;
using Spring.Context.Support;
@@ -74,6 +77,44 @@ namespace Spring.Reflection.Dynamic
Assert.AreEqual(mostImportantDayInTheWorldEver.Year, year.GetValue(mostImportantDayInTheWorldEver));
}
+ [Test]
+ public void AccessInheritedPropertyFromBaseClass()
+ {
+ IDynamicProperty p = Create(typeof(ClassWithNonReadableProperty).GetProperty("MyBaseProperty"));
+ BaseClass baseObject = new BaseClass();
+ baseObject.MyBaseProperty = "testtext";
+ Assert.AreEqual("testtext", p.GetValue(baseObject));
+ }
+
+ [Test]
+ public void AccessInheritedPropertyFromDerivedClass()
+ {
+ IDynamicProperty p = Create(typeof(BaseClass).GetProperty("MyBaseProperty"));
+ ClassWithNonReadableProperty derivedObject = new ClassWithNonReadableProperty();
+ derivedObject.MyBaseProperty = "testtext";
+ Assert.AreEqual("testtext", p.GetValue(derivedObject));
+ }
+
+ [Test]
+ public void AccessOverriddenProperty()
+ {
+ IDynamicProperty pVirt = Create(typeof(BaseClass).GetProperty("MyVirtualBaseProperty"));
+ IDynamicProperty pOverridden = Create(typeof(ClassWithNonReadableProperty).GetProperty("MyVirtualBaseProperty"));
+
+ Assert.AreEqual("MyVirtualBasePropertyText", pVirt.GetValue(new BaseClass()));
+ try
+ {
+ Assert.AreEqual("MyVirtualBasePropertyText", pOverridden.GetValue(new BaseClass()));
+ Assert.Fail();
+ }
+ catch (InvalidCastException)
+ {
+ }
+ Assert.AreEqual("MyOverridenDerivedPropertyText", pVirt.GetValue(new ClassWithNonReadableProperty()));
+ Assert.AreEqual("MyOverridenDerivedPropertyText", pOverridden.GetValue(new ClassWithNonReadableProperty()));
+ }
+
+
[Test]
public void TestStaticProperties()
{
@@ -178,7 +219,7 @@ namespace Spring.Reflection.Dynamic
#region IL generation helper classes (they help if you look at them in Reflector ;-)
- public class ValueTypeProperty : IDynamicProperty
+ public class ValueTypeProperty //: IDynamicProperty
{
public object GetValue(object target)
{
@@ -191,7 +232,7 @@ namespace Spring.Reflection.Dynamic
}
}
- public class ValueTypeTarget : IDynamicProperty
+ public class ValueTypeTarget //: IDynamicProperty
{
public object GetValue(object target)
{
@@ -205,7 +246,7 @@ namespace Spring.Reflection.Dynamic
}
}
- public class StaticProperty : IDynamicProperty
+ public class StaticProperty //: IDynamicProperty
{
public object GetValue(object target)
{
@@ -256,7 +297,23 @@ namespace Spring.Reflection.Dynamic
}
}
- public class ClassWithNonReadableProperty
+ public class BaseClass
+ {
+ private string myBaseProperty;
+
+ public string MyBaseProperty
+ {
+ set { myBaseProperty = value; }
+ get { return myBaseProperty; }
+ }
+
+ public virtual string MyVirtualBaseProperty
+ {
+ get { return "MyVirtualBasePropertyText"; }
+ }
+ }
+
+ public class ClassWithNonReadableProperty : BaseClass
{
private string myProperty;
@@ -264,6 +321,11 @@ namespace Spring.Reflection.Dynamic
{
set { myProperty = value; }
}
+
+ public override string MyVirtualBaseProperty
+ {
+ get { return "MyOverridenDerivedPropertyText"; }
+ }
}
#if NET_2_0
diff --git a/test/Spring/Spring.Core.Tests/Reflection/Dynamic/DynamicMethodTests.cs b/test/Spring/Spring.Core.Tests/Reflection/Dynamic/DynamicMethodTests.cs
index b4933522..e48f5392 100644
--- a/test/Spring/Spring.Core.Tests/Reflection/Dynamic/DynamicMethodTests.cs
+++ b/test/Spring/Spring.Core.Tests/Reflection/Dynamic/DynamicMethodTests.cs
@@ -108,6 +108,38 @@ namespace Spring.Reflection.Dynamic
Assert.IsFalse((bool) isNullOrEmpty.Invoke(null, new object[] { "Ana Maria" }));
}
+ [Test]
+ public void TestArgumentTypeCasts()
+ {
+ IDynamicMethod sqrt = DynamicMethod.Create(typeof(Math).GetMethod("Sqrt"));
+ object result = sqrt.Invoke(null, new object[] { 4 } );
+ Assert.AreEqual( Math.Sqrt(4), result );
+
+ try
+ {
+ sqrt.Invoke(null, new object[] { null } );
+ Assert.Fail();
+ }
+ catch (InvalidCastException)
+ {
+ }
+
+ try
+ {
+ sqrt.Invoke(null, new object[] { "4" } );
+ Assert.Fail();
+ }
+ catch (InvalidCastException)
+ {}
+ }
+
+ private void CodeForReflection()
+ {
+ object val = 4;
+ Type argType = typeof(double);
+ Math.Sqrt( (double)Convert.ChangeType(val, argType) );
+ }
+
[Test]
public void TestRefOutMethods()
{
diff --git a/test/Spring/Spring.Core.Tests/Reflection/Dynamic/DynamicPropertyTests.cs b/test/Spring/Spring.Core.Tests/Reflection/Dynamic/DynamicPropertyTests.cs
index 69978cc0..a789751e 100644
--- a/test/Spring/Spring.Core.Tests/Reflection/Dynamic/DynamicPropertyTests.cs
+++ b/test/Spring/Spring.Core.Tests/Reflection/Dynamic/DynamicPropertyTests.cs
@@ -21,8 +21,11 @@
#region Imports
using System;
+using System.CodeDom.Compiler;
using System.Diagnostics;
+using System.IO;
using System.Reflection;
+using System.Text;
using NUnit.Framework;
using Spring.Context.Support;
@@ -30,52 +33,52 @@ using Spring.Context.Support;
namespace Spring.Reflection.Dynamic
{
- ///
+ ///
/// Unit tests for the DynamicProperty class.
///
/// Aleksandar Seovic
- [TestFixture]
+ [TestFixture]
public class DynamicPropertyTests : BasePropertyTests
{
- protected override IDynamicProperty Create(PropertyInfo property)
+ protected override IDynamicProperty Create( PropertyInfo property )
{
- return DynamicProperty.Create(property);
+ return DynamicProperty.Create( property );
}
[Test]
- [ExpectedException(typeof(InvalidOperationException))]
+ [ExpectedException( typeof( InvalidOperationException ) )]
public void TestNonReadableProperties()
{
- IDynamicProperty nonReadableProperty =
- Create(typeof(ClassWithNonReadableProperty).GetProperty("MyProperty"));
- nonReadableProperty.GetValue(null);
+ IDynamicProperty nonReadableProperty =
+ Create( typeof( ClassWithNonReadableProperty ).GetProperty( "MyProperty" ) );
+ nonReadableProperty.GetValue( null );
}
[Test]
- [ExpectedException(typeof(InvalidOperationException))]
+ [ExpectedException( typeof( InvalidOperationException ) )]
public void TestNonWritableInstanceProperty()
{
IDynamicProperty nonWritableProperty =
- Create(typeof(Inventor).GetProperty("PlaceOfBirth"));
- nonWritableProperty.SetValue(null, null);
+ Create( typeof( Inventor ).GetProperty( "PlaceOfBirth" ) );
+ nonWritableProperty.SetValue( null, null );
}
[Test]
- [ExpectedException(typeof(InvalidOperationException))]
+ [ExpectedException( typeof( InvalidOperationException ) )]
public void TestAttemptingToSetPropertyOfValueTypeInstance()
{
MyStruct myYearHolder = new MyStruct();
- IDynamicProperty year = Create(typeof(MyStruct).GetProperty("Year"));
- year.SetValue(myYearHolder, 2004);
+ IDynamicProperty year = Create( typeof( MyStruct ).GetProperty( "Year" ) );
+ year.SetValue( myYearHolder, 2004 );
}
-
+
[Test]
- [ExpectedException(typeof(InvalidOperationException))]
+ [ExpectedException( typeof( InvalidOperationException ) )]
public void TestNonWritableStaticProperty()
{
IDynamicProperty nonWritableProperty =
- Create(typeof(DateTime).GetProperty("Today"));
- nonWritableProperty.SetValue(null, null);
- }
+ Create( typeof( DateTime ).GetProperty( "Today" ) );
+ nonWritableProperty.SetValue( null, null );
+ }
}
}
diff --git a/test/Spring/Spring.Core.Tests/Reflection/Dynamic/SafePropertyTests.cs b/test/Spring/Spring.Core.Tests/Reflection/Dynamic/SafePropertyTests.cs
index 0b3407bc..b37f1624 100644
--- a/test/Spring/Spring.Core.Tests/Reflection/Dynamic/SafePropertyTests.cs
+++ b/test/Spring/Spring.Core.Tests/Reflection/Dynamic/SafePropertyTests.cs
@@ -21,7 +21,11 @@
#region Imports
using System;
+using System.CodeDom.Compiler;
+using System.IO;
using System.Reflection;
+using System.Text;
+using Microsoft.VisualBasic;
using NUnit.Framework;
#endregion
@@ -41,6 +45,53 @@ namespace Spring.Reflection.Dynamic
return new SafeProperty(property);
}
+
+ [Test]
+ public void CanGetSetSimpleProperty()
+ {
+ object o = GetVisualBasicTestObject();
+ IDynamicProperty simpleProperty = Create(o.GetType().GetProperty("SimpleProperty"));
+ simpleProperty.SetValue(o, "CanGetSimpleText", "args");
+ Assert.AreEqual("CanGetSimpleText", ThisLastPropertyValue.GetValue(o));
+ Assert.AreEqual("CanGetSimpleText", simpleProperty.GetValue(o));
+ }
+
+ [Test]
+ public void CanGetSetSimpleIndexer()
+ {
+ object o = GetVisualBasicTestObject();
+ IDynamicProperty simpleProperty = Create(o.GetType().GetProperty("SimpleIndexer"));
+
+ // write
+ simpleProperty.SetValue(o, "CanGetSetSimpleIndexer", 2);
+ Assert.AreEqual("CanGetSetSimpleIndexer", ThisLastPropertyValue.GetValue(o));
+ Assert.AreEqual(2, ThisArg1.GetValue(o));
+
+ // read
+ object value = simpleProperty.GetValue(o, 3);
+ Assert.AreEqual("CanGetSetSimpleIndexer", value);
+ Assert.AreEqual(3, ThisArg1.GetValue(o));
+ }
+
+ [Test]
+ public void CanGetSetComplexIndexer()
+ {
+ object o = GetVisualBasicTestObject();
+ IDynamicProperty property = Create(o.GetType().GetProperty("ComplexIndexer"));
+
+ // write
+ property.SetValue(o, "CanGetSetComplexIndexer", 2, "Arg2");
+ Assert.AreEqual("CanGetSetComplexIndexer", ThisLastPropertyValue.GetValue(o));
+ Assert.AreEqual(2.0, (double)ThisArg1.GetValue(o));
+ Assert.AreEqual("Arg2", ThisArg2.GetValue(o));
+
+ // read
+ object value = property.GetValue(o, 3, "Arg3");
+ Assert.AreEqual("CanGetSetComplexIndexer", value);
+ Assert.AreEqual(3.0, (double)ThisArg1.GetValue(o));
+ Assert.AreEqual("Arg3", ThisArg2.GetValue(o));
+ }
+
#if NET_2_0
[Test]
public void TestForRestrictiveSetterWithSafeWrapper()
@@ -76,6 +127,60 @@ namespace Spring.Reflection.Dynamic
Assert.AreEqual(123, first.GetValue(something));
}
#endif
+
+ #region VB TestClass Code
+
+ private static Type s__visualBasicTestObjectType;
+ private static IDynamicField ThisLastPropertyValue;
+ private static IDynamicField ThisArg1;
+ private static IDynamicField ThisArg2;
+ private static IDynamicField ThisOptionalArg;
+ private static IDynamicField ThisParamsArg;
+
+ protected static object GetVisualBasicTestObject()
+ {
+ if (s__visualBasicTestObjectType == null)
+ {
+ // compile vb test class
+ string vbSourceCode = new StreamReader( Assembly.GetExecutingAssembly().GetManifestResourceStream( typeof( BasePropertyTests ), "SafePropertyTests_TestObject.vb" ) ).ReadToEnd();
+
+ CompilerParameters args = new CompilerParameters();
+ args.OutputAssembly = "VbTestObject.dll";
+ args.GenerateInMemory = true;
+ args.GenerateExecutable = false;
+ args.IncludeDebugInformation = true;
+ args.Evidence = Assembly.GetExecutingAssembly().Evidence;
+#if NET_2_0
+ CodeDomProvider provider = CodeDomProvider.CreateProvider( "VisualBasic" );
+ CompilerResults results = provider.CompileAssemblyFromSource( args, vbSourceCode );
+#else
+ CodeDomProvider provider = new VBCodeProvider();
+ ICodeCompiler compiler = provider.CreateCompiler();
+ CompilerResults results = compiler.CompileAssemblyFromSource( args, vbSourceCode );
+#endif
+ if (results.Errors.HasErrors)
+ {
+ StringBuilder sb = new StringBuilder();
+ foreach (CompilerError error in results.Errors)
+ {
+ sb.Append( error.ToString() ).Append( "\n\r" );
+ }
+ throw new TypeLoadException( "failed compiling test class: " + sb );
+ }
+ s__visualBasicTestObjectType = results.CompiledAssembly.GetType( "VbTestObject" );
+ ThisLastPropertyValue = DynamicField.Create( s__visualBasicTestObjectType.GetField("ThisLastPropertyValue") );
+ ThisArg1 = DynamicField.Create( s__visualBasicTestObjectType.GetField("ThisArg1") );
+ ThisArg2 = DynamicField.Create( s__visualBasicTestObjectType.GetField("ThisArg2") );
+ ThisOptionalArg = DynamicField.Create( s__visualBasicTestObjectType.GetField("ThisOptionalArg") );
+ ThisParamsArg = DynamicField.Create( s__visualBasicTestObjectType.GetField("ThisParamsArgs") );
+ }
+
+ object s__visualBasicTestObject = Activator.CreateInstance(s__visualBasicTestObjectType);
+
+ return s__visualBasicTestObject;
+ }
+
+ #endregion
}
#region Test Classes
diff --git a/test/Spring/Spring.Core.Tests/Reflection/Dynamic/SafePropertyTests_TestObject.vb b/test/Spring/Spring.Core.Tests/Reflection/Dynamic/SafePropertyTests_TestObject.vb
new file mode 100644
index 00000000..b0708492
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Reflection/Dynamic/SafePropertyTests_TestObject.vb
@@ -0,0 +1,68 @@
+Public Class VbTestObject
+ Public ThisArg1 As Object
+ Public ThisArg2 As Object
+ Public ThisOptionalArg As Object
+ Public ThisParamsArgs As Object()
+ Public ThisLastPropertyValue As Object
+
+ Property SimpleProperty() As String
+ Get
+ Return ThisLastPropertyValue
+ End Get
+ Set(ByVal value As String)
+ ThisLastPropertyValue = value
+ End Set
+ End Property
+
+ Property SimpleIndexer(ByVal arg1 As Integer) As String
+ Get
+ ThisArg1 = arg1
+ Return ThisLastPropertyValue
+ End Get
+ Set(ByVal value As String)
+ ThisArg1 = arg1
+ ThisLastPropertyValue = value
+ End Set
+ End Property
+
+ Default Property ComplexIndexer(ByVal arg1 As Double, ByVal arg2 As Object) As String
+ Get
+ ThisArg1 = arg1
+ ThisArg2 = arg2
+ Return ThisLastPropertyValue
+ End Get
+ Set(ByVal value As String)
+ ThisArg1 = arg1
+ ThisArg2 = arg2
+ ThisLastPropertyValue = value
+ End Set
+ End Property
+
+ Property PropertyWithParamsArgs(ByVal arg1 As String, ByVal ParamArray paramsArgs As Object()) As String
+ Get
+ ThisArg1 = arg1
+ ThisParamsArgs = paramsArgs
+ Return ThisLastPropertyValue
+ End Get
+ Set(ByVal value As String)
+ ThisArg1 = arg1
+ ThisParamsArgs = paramsArgs
+ ThisLastPropertyValue = value
+ End Set
+ End Property
+
+
+ Property PropertyWithOptionalArg(ByVal arg1 As String, Optional ByVal optionalArg As Object = "Empty") As String
+ Get
+ ThisArg1 = arg1
+ ThisOptionalArg = optionalArg
+ Return ThisLastPropertyValue
+ End Get
+ Set(ByVal value As String)
+ ThisArg1 = arg1
+ ThisOptionalArg = optionalArg
+ ThisLastPropertyValue = value
+ End Set
+ End Property
+
+End Class
\ No newline at end of file
diff --git a/test/Spring/Spring.Core.Tests/Spring.Core.Tests.2003.csproj b/test/Spring/Spring.Core.Tests/Spring.Core.Tests.2003.csproj
index 58be75c1..61ea52cc 100644
--- a/test/Spring/Spring.Core.Tests/Spring.Core.Tests.2003.csproj
+++ b/test/Spring/Spring.Core.Tests/Spring.Core.Tests.2003.csproj
@@ -1744,6 +1744,10 @@
SubType = "Code"
BuildAction = "Compile"
/>
+
Code
+
diff --git a/test/Spring/Spring.Core.Tests/Spring.Core.Tests.build b/test/Spring/Spring.Core.Tests/Spring.Core.Tests.build
index a1085c2d..1345f8f0 100644
--- a/test/Spring/Spring.Core.Tests/Spring.Core.Tests.build
+++ b/test/Spring/Spring.Core.Tests/Spring.Core.Tests.build
@@ -30,6 +30,7 @@
+
diff --git a/test/Spring/Spring.Data.Integration.Tests/Spring.Data.Integration.Tests.2003.csproj b/test/Spring/Spring.Data.Integration.Tests/Spring.Data.Integration.Tests.2003.csproj
index 89fe78d2..deacee02 100644
--- a/test/Spring/Spring.Data.Integration.Tests/Spring.Data.Integration.Tests.2003.csproj
+++ b/test/Spring/Spring.Data.Integration.Tests/Spring.Data.Integration.Tests.2003.csproj
@@ -151,6 +151,11 @@
SubType = "Code"
BuildAction = "Compile"
/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Local
- 9.0.21022
+ 9.0.30729
2.0
{91766D21-C568-459F-9BEA-759B011F23CF}
Debug
@@ -127,6 +127,7 @@
+
@@ -185,6 +186,12 @@
+
+
+
+
+
+
diff --git a/test/Spring/Spring.Web.Tests/Spring.Web.Tests.2003.csproj b/test/Spring/Spring.Web.Tests/Spring.Web.Tests.2003.csproj
index cd511db9..4abdc4fb 100644
--- a/test/Spring/Spring.Web.Tests/Spring.Web.Tests.2003.csproj
+++ b/test/Spring/Spring.Web.Tests/Spring.Web.Tests.2003.csproj
@@ -244,6 +244,11 @@
SubType = "Code"
BuildAction = "Compile"
/>
+
+
-
-
+
+
+
+
/// Unit tests for the ControlInterceptor class.
@@ -40,7 +40,7 @@ namespace Spring.Util
public class ControlInterceptionTests
{
private const string RES_OBJECTS =
- "assembly://Spring.Web.Tests/Spring.Util/ControlInterceptionTests.objects.xml";
+ "assembly://Spring.Web.Tests/Spring.Web.Support/ControlInterceptionTests.objects.xml";
static ControlInterceptionTests()
{
diff --git a/test/Spring/Spring.Web.Tests/Util/ControlInterceptionTests.objects.xml b/test/Spring/Spring.Web.Tests/Web/Support/ControlInterceptionTests.objects.xml
similarity index 68%
rename from test/Spring/Spring.Web.Tests/Util/ControlInterceptionTests.objects.xml
rename to test/Spring/Spring.Web.Tests/Web/Support/ControlInterceptionTests.objects.xml
index 320c4faf..ae4dccfa 100644
--- a/test/Spring/Spring.Web.Tests/Util/ControlInterceptionTests.objects.xml
+++ b/test/Spring/Spring.Web.Tests/Web/Support/ControlInterceptionTests.objects.xml
@@ -2,7 +2,7 @@
-