Skip to content

NH-3964 - Refactor reflection patterns #574

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Mar 23, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/NHibernate.Test/NHSpecificTest/NH3964/Fixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System.Collections;
using NHibernate.Util;
using NUnit.Framework;

namespace NHibernate.Test.NHSpecificTest.NH3964
{
[TestFixture]
public class Fixture
{
[Test(Description = "Test for removal of a workaround for an old Fx bug (<v4)")]
public void AddingNullToNonGenericListShouldNotThrow()
{
var a1 = new ArrayList { null };
var a2 = new ArrayList();
Assert.DoesNotThrow(() => ArrayHelper.AddAll(a2, a1));
}
}
}
1 change: 1 addition & 0 deletions src/NHibernate.Test/NHibernate.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,7 @@
<Compile Include="NHSpecificTest\NH3961\DateParametersComparedTo.cs" />
<Compile Include="NHSpecificTest\NH3963\Entity.cs" />
<Compile Include="NHSpecificTest\NH3963\MappedAsFixture.cs" />
<Compile Include="NHSpecificTest\NH3964\Fixture.cs" />
<Compile Include="NHSpecificTest\NH3950\Entity.cs" />
<Compile Include="NHSpecificTest\NH3950\Fixture.cs" />
<Compile Include="NHSpecificTest\NH3952\Entity.cs" />
Expand Down
18 changes: 8 additions & 10 deletions src/NHibernate/Bytecode/EmitUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
using System.Reflection;
using System.Reflection.Emit;
using System.Collections.Generic;
using NHibernate.Linq;
using NHibernate.Util;

namespace NHibernate.Bytecode
{
Expand Down Expand Up @@ -185,28 +187,24 @@ public static System.Type DefineDelegateType(
public static void EmitLoadType(ILGenerator il, System.Type type)
{
il.Emit(OpCodes.Ldtoken, type);
il.Emit(OpCodes.Call, typeof(System.Type).GetMethod("GetTypeFromHandle"));
il.Emit(OpCodes.Call, ReflectionCache.TypeMethods.GetTypeFromHandle);
}

public static void EmitLoadMethodInfo(ILGenerator il, MethodInfo methodInfo)
{
il.Emit(OpCodes.Ldtoken, methodInfo);
il.Emit(
OpCodes.Call,
typeof(MethodBase).GetMethod(
"GetMethodFromHandle", new System.Type[] {typeof(RuntimeMethodHandle)}));
il.Emit(OpCodes.Call, ReflectionCache.MethodBaseMethods.GetMethodFromHandle);
il.Emit(OpCodes.Castclass, typeof(MethodInfo));
}

private static readonly MethodInfo CreateDelegate = ReflectionHelper.GetMethod(
() => Delegate.CreateDelegate(null, null));

public static void EmitCreateDelegateInstance(ILGenerator il, System.Type delegateType, MethodInfo methodInfo)
{
MethodInfo createDelegate = typeof(Delegate).GetMethod(
"CreateDelegate", BindingFlags.Static | BindingFlags.Public | BindingFlags.ExactBinding, null,
new System.Type[] {typeof(System.Type), typeof(MethodInfo)}, null);

EmitLoadType(il, delegateType);
EmitLoadMethodInfo(il, methodInfo);
il.EmitCall(OpCodes.Call, createDelegate, null);
il.EmitCall(OpCodes.Call, CreateDelegate, null);
il.Emit(OpCodes.Castclass, delegateType);
}
}
Expand Down
13 changes: 9 additions & 4 deletions src/NHibernate/Bytecode/Lightweight/ReflectionOptimizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Reflection.Emit;
using System.Security;
using System.Security.Permissions;
using NHibernate.Linq;
using NHibernate.Properties;
using NHibernate.Util;

Expand Down Expand Up @@ -118,6 +119,9 @@ private static void EmitCastToReference(ILGenerator il, System.Type type)
}
}

private static readonly MethodInfo GetterCallbackInvoke = ReflectionHelper.GetMethod<GetterCallback>(
g => g.Invoke(null, 0));

/// <summary>
/// Generates a dynamic method on the given type.
/// </summary>
Expand Down Expand Up @@ -163,8 +167,7 @@ private GetPropertyValuesInvoker GenerateGetPropertyValuesMethod(IGetter[] gette
else
{
// using the getter itself via a callback
MethodInfo invokeMethod = typeof (GetterCallback).GetMethod("Invoke",
new[] {typeof (object), typeof (int)});
MethodInfo invokeMethod = GetterCallbackInvoke;
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldc_I4, i);
Expand All @@ -182,6 +185,9 @@ private GetPropertyValuesInvoker GenerateGetPropertyValuesMethod(IGetter[] gette
return (GetPropertyValuesInvoker) method.CreateDelegate(typeof (GetPropertyValuesInvoker));
}

private static readonly MethodInfo SetterCallbackInvoke = ReflectionHelper.GetMethod<SetterCallback>(
g => g.Invoke(null, 0, null));

/// <summary>
/// Generates a dynamic method on the given type.
/// </summary>
Expand Down Expand Up @@ -224,8 +230,7 @@ private SetPropertyValuesInvoker GenerateSetPropertyValuesMethod(ISetter[] sette
else
{
// using the setter itself via a callback
MethodInfo invokeMethod = typeof (SetterCallback).GetMethod("Invoke",
new[] {typeof (object), typeof (int), typeof (object)});
MethodInfo invokeMethod = SetterCallbackInvoke;
il.Emit(OpCodes.Ldarg_2);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldc_I4, i);
Expand Down
14 changes: 5 additions & 9 deletions src/NHibernate/Linq/DefaultQueryProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,17 +79,13 @@ protected virtual NhLinqExpression PrepareQuery(Expression expression, out IQuer
return nhLinqExpression;
}

private static readonly MethodInfo Future = ReflectionHelper.GetMethodDefinition<IQuery>(q => q.Future<object>());
private static readonly MethodInfo FutureValue = ReflectionHelper.GetMethodDefinition<IQuery>(q => q.FutureValue<object>());

protected virtual object ExecuteFutureQuery(NhLinqExpression nhLinqExpression, IQuery query, NhLinqExpression nhQuery)
{
MethodInfo method;
if (nhLinqExpression.ReturnType == NhLinqExpressionReturnType.Sequence)
{
method = typeof (IQuery).GetMethod("Future").MakeGenericMethod(nhQuery.Type);
}
else
{
method = typeof (IQuery).GetMethod("FutureValue").MakeGenericMethod(nhQuery.Type);
}
var method = (nhLinqExpression.ReturnType == NhLinqExpressionReturnType.Sequence ? Future : FutureValue)
.MakeGenericMethod(nhQuery.Type);

object result = method.Invoke(query, new object[0]);

Expand Down
26 changes: 17 additions & 9 deletions src/NHibernate/Linq/NhRelinqQueryParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,26 @@ public NHibernateNodeTypeProvider()
{
var methodInfoRegistry = new MethodInfoBasedNodeTypeRegistry();

methodInfoRegistry.Register(new[] { typeof(EagerFetchingExtensionMethods).GetMethod("Fetch") }, typeof(FetchOneExpressionNode));
methodInfoRegistry.Register(new[] { typeof(EagerFetchingExtensionMethods).GetMethod("FetchMany") }, typeof(FetchManyExpressionNode));
methodInfoRegistry.Register(new[] { typeof(EagerFetchingExtensionMethods).GetMethod("ThenFetch") }, typeof(ThenFetchOneExpressionNode));
methodInfoRegistry.Register(new[] { typeof(EagerFetchingExtensionMethods).GetMethod("ThenFetchMany") }, typeof(ThenFetchManyExpressionNode));
methodInfoRegistry.Register(
new[] { ReflectionHelper.GetMethodDefinition(() => EagerFetchingExtensionMethods.Fetch<object, object>(null, null)) },
typeof(FetchOneExpressionNode));
methodInfoRegistry.Register(
new[] { ReflectionHelper.GetMethodDefinition(() => EagerFetchingExtensionMethods.FetchMany<object, object>(null, null)) },
typeof(FetchManyExpressionNode));
methodInfoRegistry.Register(
new[] { ReflectionHelper.GetMethodDefinition(() => EagerFetchingExtensionMethods.ThenFetch<object, object, object>(null, null)) },
typeof(ThenFetchOneExpressionNode));
methodInfoRegistry.Register(
new[] { ReflectionHelper.GetMethodDefinition(() => EagerFetchingExtensionMethods.ThenFetchMany<object, object, object>(null, null)) },
typeof(ThenFetchManyExpressionNode));

methodInfoRegistry.Register(
new[]
{
typeof(LinqExtensionMethods).GetMethod("Cacheable"),
typeof(LinqExtensionMethods).GetMethod("CacheMode"),
typeof(LinqExtensionMethods).GetMethod("CacheRegion"),
}, typeof(CacheableExpressionNode));
{
ReflectionHelper.GetMethodDefinition(() => LinqExtensionMethods.Cacheable<object>(null)),
ReflectionHelper.GetMethodDefinition(() => LinqExtensionMethods.CacheMode<object>(null, CacheMode.Normal)),
ReflectionHelper.GetMethodDefinition(() => LinqExtensionMethods.CacheRegion<object>(null, null)),
}, typeof(CacheableExpressionNode));

methodInfoRegistry.Register(
new[]
Expand Down
15 changes: 11 additions & 4 deletions src/NHibernate/Linq/Visitors/ExpressionParameterVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,19 @@ public class ExpressionParameterVisitor : ExpressionTreeVisitor
private readonly Dictionary<ConstantExpression, NamedParameter> _parameters = new Dictionary<ConstantExpression, NamedParameter>();
private readonly ISessionFactoryImplementor _sessionFactory;

private static readonly MethodInfo QueryableSkipDefinition =
ReflectionHelper.GetMethodDefinition(() => Queryable.Skip<object>(null, 0));
private static readonly MethodInfo QueryableTakeDefinition =
ReflectionHelper.GetMethodDefinition(() => Queryable.Take<object>(null, 0));
private static readonly MethodInfo EnumerableSkipDefinition =
ReflectionHelper.GetMethodDefinition(() => Enumerable.Skip<object>(null, 0));
private static readonly MethodInfo EnumerableTakeDefinition =
ReflectionHelper.GetMethodDefinition(() => Enumerable.Take<object>(null, 0));

private readonly ICollection<MethodBase> _pagingMethods = new HashSet<MethodBase>
{
ReflectionHelper.GetMethodDefinition(() => Queryable.Skip<object>(null, 0)),
ReflectionHelper.GetMethodDefinition(() => Queryable.Take<object>(null, 0)),
ReflectionHelper.GetMethodDefinition(() => Enumerable.Skip<object>(null, 0)),
ReflectionHelper.GetMethodDefinition(() => Enumerable.Take<object>(null, 0)),
QueryableSkipDefinition, QueryableTakeDefinition,
EnumerableSkipDefinition, EnumerableTakeDefinition
};

public ExpressionParameterVisitor(ISessionFactoryImplementor sessionFactory)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
using System.Linq;
using System.Reflection;
using Remotion.Linq.Clauses.ResultOperators;

namespace NHibernate.Linq.Visitors.ResultOperatorProcessors
{
public class ProcessFirst : ProcessFirstOrSingleBase, IResultOperatorProcessor<FirstResultOperator>
{
public void Process(FirstResultOperator resultOperator, QueryModelVisitor queryModelVisitor, IntermediateHqlTree tree)
{
var firstMethod = resultOperator.ReturnDefaultWhenEmpty
? ReflectionHelper.GetMethodDefinition(() => Queryable.FirstOrDefault<object>(null))
: ReflectionHelper.GetMethodDefinition(() => Queryable.First<object>(null));
public class ProcessFirst : ProcessFirstOrSingleBase, IResultOperatorProcessor<FirstResultOperator>
{
private static readonly MethodInfo FirstOrDefault =
ReflectionHelper.GetMethodDefinition(() => Queryable.FirstOrDefault<object>(null));
private static readonly MethodInfo First =
ReflectionHelper.GetMethodDefinition(() => Queryable.First<object>(null));

AddClientSideEval(firstMethod, queryModelVisitor, tree);
public void Process(FirstResultOperator resultOperator, QueryModelVisitor queryModelVisitor, IntermediateHqlTree tree)
{
var firstMethod = resultOperator.ReturnDefaultWhenEmpty ? FirstOrDefault : First;

tree.AddTakeClause(tree.TreeBuilder.Constant(1));
}
}
AddClientSideEval(firstMethod, queryModelVisitor, tree);

tree.AddTakeClause(tree.TreeBuilder.Constant(1));
}
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
using System.Linq;
using System.Reflection;
using Remotion.Linq.Clauses.ResultOperators;

namespace NHibernate.Linq.Visitors.ResultOperatorProcessors
{
public class ProcessSingle : ProcessFirstOrSingleBase, IResultOperatorProcessor<SingleResultOperator>
{
public void Process(SingleResultOperator resultOperator, QueryModelVisitor queryModelVisitor, IntermediateHqlTree tree)
{
var firstMethod = resultOperator.ReturnDefaultWhenEmpty
? ReflectionHelper.GetMethodDefinition(() => Queryable.SingleOrDefault<object>(null))
: ReflectionHelper.GetMethodDefinition(() => Queryable.Single<object>(null));
public class ProcessSingle : ProcessFirstOrSingleBase, IResultOperatorProcessor<SingleResultOperator>
{
private static readonly MethodInfo SingleOrDefault =
ReflectionHelper.GetMethodDefinition(() => Queryable.SingleOrDefault<object>(null));
private static readonly MethodInfo Single =
ReflectionHelper.GetMethodDefinition(() => Queryable.Single<object>(null));

AddClientSideEval(firstMethod, queryModelVisitor, tree);
}
}
public void Process(SingleResultOperator resultOperator, QueryModelVisitor queryModelVisitor, IntermediateHqlTree tree)
{
var firstMethod = resultOperator.ReturnDefaultWhenEmpty ? SingleOrDefault : Single;

AddClientSideEval(firstMethod, queryModelVisitor, tree);
}
}
}
19 changes: 8 additions & 11 deletions src/NHibernate/Proxy/DynamicProxy/DefaultMethodEmitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,18 @@
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using NHibernate.Linq;
using NHibernate.Util;

namespace NHibernate.Proxy.DynamicProxy
{
internal class DefaultMethodEmitter : IMethodBodyEmitter
{
private static readonly MethodInfo getInterceptor;

private static readonly MethodInfo getGenericMethodFromHandle = typeof (MethodBase).GetMethod("GetMethodFromHandle",
BindingFlags.Public | BindingFlags.Static, null,
new[] {typeof (RuntimeMethodHandle), typeof (RuntimeTypeHandle)}, null);

private static readonly MethodInfo getMethodFromHandle = typeof (MethodBase).GetMethod("GetMethodFromHandle", new[] {typeof (RuntimeMethodHandle)});
private static readonly MethodInfo getTypeFromHandle = typeof(System.Type).GetMethod("GetTypeFromHandle");
private static readonly MethodInfo handlerMethod = typeof (IInterceptor).GetMethod("Intercept");
private static readonly MethodInfo handlerMethod = ReflectionHelper.GetMethod<IInterceptor>(
i => i.Intercept(null));
private static readonly MethodInfo getArguments = typeof(InvocationInfo).GetMethod("get_Arguments");

private static readonly ConstructorInfo infoConstructor = typeof (InvocationInfo).GetConstructor(new[]
{
Expand Down Expand Up @@ -118,7 +116,6 @@ private static void EmitBaseMethodCall(ILGenerator IL, MethodInfo method)
private static void SaveRefArguments(ILGenerator IL, ParameterInfo[] parameters)
{
// Save the arguments returned from the handler method
MethodInfo getArguments = typeof (InvocationInfo).GetMethod("get_Arguments");
IL.Emit(OpCodes.Ldloc_1);
IL.Emit(OpCodes.Call, getArguments);
IL.Emit(OpCodes.Stloc_0);
Expand Down Expand Up @@ -192,11 +189,11 @@ private static void PushTargetMethodInfo(ILGenerator IL, MethodBuilder generated
if (declaringType.IsGenericType)
{
IL.Emit(OpCodes.Ldtoken, declaringType);
IL.Emit(OpCodes.Call, getGenericMethodFromHandle);
IL.Emit(OpCodes.Call, ReflectionCache.MethodBaseMethods.GetMethodFromHandleWithDeclaringType);
}
else
{
IL.Emit(OpCodes.Call, getMethodFromHandle);
IL.Emit(OpCodes.Call, ReflectionCache.MethodBaseMethods.GetMethodFromHandle);
}

IL.Emit(OpCodes.Castclass, typeof(MethodInfo));
Expand Down Expand Up @@ -232,7 +229,7 @@ private void PushGenericArguments(MethodInfo method, ILGenerator IL)
IL.Emit(OpCodes.Dup);
IL.Emit(OpCodes.Ldc_I4, index);
IL.Emit(OpCodes.Ldtoken, currentType);
IL.Emit(OpCodes.Call, getTypeFromHandle);
IL.Emit(OpCodes.Call, ReflectionCache.TypeMethods.GetTypeFromHandle);
IL.Emit(OpCodes.Stelem_Ref);
}
}
Expand Down
20 changes: 10 additions & 10 deletions src/NHibernate/Proxy/DynamicProxy/ProxyFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,21 @@
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.Serialization;
using NHibernate.Linq;
using NHibernate.Util;

namespace NHibernate.Proxy.DynamicProxy
{
public sealed class ProxyFactory
{
private static readonly ConstructorInfo defaultBaseConstructor = typeof(object).GetConstructor(new System.Type[0]);
private static readonly MethodInfo getTypeFromHandle = typeof(System.Type).GetMethod("GetTypeFromHandle");

private static readonly MethodInfo getValue = typeof (SerializationInfo).GetMethod("GetValue", BindingFlags.Public | BindingFlags.Instance, null,
new[] { typeof(string), typeof(System.Type) }, null);

private static readonly MethodInfo setType = typeof(SerializationInfo).GetMethod("SetType", BindingFlags.Public | BindingFlags.Instance, null, new[] { typeof(System.Type) }, null);

private static readonly MethodInfo addValue = typeof (SerializationInfo).GetMethod("AddValue", BindingFlags.Public | BindingFlags.Instance, null,
new[] {typeof (string), typeof (object)}, null);
private static readonly MethodInfo getValue = ReflectionHelper.GetMethod<SerializationInfo>(
si => si.GetValue(null, null));
private static readonly MethodInfo setType = ReflectionHelper.GetMethod<SerializationInfo>(
si => si.SetType(null));
private static readonly MethodInfo addValue = ReflectionHelper.GetMethod<SerializationInfo>(
si => si.AddValue(null, null));

public ProxyFactory()
: this(new DefaultyProxyMethodBuilder()) {}
Expand Down Expand Up @@ -221,7 +221,7 @@ private static void ImplementGetObjectData(System.Type baseType, System.Type[] b
// info.SetType(typeof(ProxyObjectReference));
IL.Emit(OpCodes.Ldarg_1);
IL.Emit(OpCodes.Ldtoken, typeof (ProxyObjectReference));
IL.Emit(OpCodes.Call, getTypeFromHandle);
IL.Emit(OpCodes.Call, ReflectionCache.TypeMethods.GetTypeFromHandle);
IL.Emit(OpCodes.Callvirt, setType);

// info.AddValue("__interceptor", __interceptor);
Expand Down Expand Up @@ -276,7 +276,7 @@ private static void DefineSerializationConstructor(TypeBuilder typeBuilder, Fiel


IL.Emit(OpCodes.Ldtoken, typeof (IInterceptor));
IL.Emit(OpCodes.Call, getTypeFromHandle);
IL.Emit(OpCodes.Call, ReflectionCache.TypeMethods.GetTypeFromHandle);
IL.Emit(OpCodes.Stloc, interceptorType);

IL.Emit(OpCodes.Ldarg_0);
Expand Down
Loading