Skip to content

Commit 99096f8

Browse files
committed
DefaultProxyMethodBuilder.cs: Make it better at handling generic methods with various type constraints. Based on pull request #142 from cremor, but leaving out the incomplete parts. Also took the opportunity for some cleanup. NH-3244.
1 parent 5f96710 commit 99096f8

File tree

7 files changed

+125
-28
lines changed

7 files changed

+125
-28
lines changed
Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,62 @@
1-
using System.Collections.Generic;
21
using NHibernate.Proxy.DynamicProxy;
32
using NUnit.Framework;
43
using SharpTestsEx;
54

65
namespace NHibernate.Test.DynamicProxyTests.GenericMethodsTests
76
{
7+
[TestFixture]
88
public class GenericMethodShouldBeProxied
99
{
10-
public class MyClass
10+
[Test]
11+
public void CanProxyBasicGenericMethod()
1112
{
12-
public virtual object Method<T>()
13-
{
14-
if(typeof(T) == typeof(int))
15-
{
16-
return 5;
17-
}
18-
if (typeof(T) == typeof(string))
19-
{
20-
return "blha";
21-
}
22-
return default(T);
23-
}
24-
25-
public virtual TRequestedType As<TRequestedType>() where TRequestedType : MyClass
26-
{
27-
return this as TRequestedType;
28-
}
13+
var factory = new ProxyFactory();
14+
var c = (MyClass)factory.CreateProxy(typeof(MyClass), new PassThroughInterceptor(new MyClass()), null);
15+
c.BasicGenericMethod<int>().Should().Be(5);
16+
c.BasicGenericMethod<string>().Should().Be("blha");
2917
}
3018

3119
[Test]
32-
public void ProxyOfAGenericMethod()
20+
public void CanProxyMethodWithGenericBaseClassConstraint()
3321
{
3422
var factory = new ProxyFactory();
3523
var c = (MyClass)factory.CreateProxy(typeof(MyClass), new PassThroughInterceptor(new MyClass()), null);
36-
c.Method<int>().Should().Be(5);
37-
c.Method<string>().Should().Be("blha");
24+
c.MethodWithGenericBaseClassConstraint<MyGenericClass<int>, int>().Should().Be(typeof(MyGenericClass<int>));
3825
}
3926

4027
[Test]
41-
public void ProxyOfSelfCastingMethod()
28+
public void CanProxySelfCastingMethod()
4229
{
4330
var factory = new ProxyFactory();
4431
var c = (MyClass)factory.CreateProxy(typeof(MyClass), new PassThroughInterceptor(new MyClass()), null);
4532
c.As<MyClass>().Should().Not.Be.Null();
4633
}
34+
35+
[Test]
36+
public void CanProxyMethodWithDefaultConstructorConstraint()
37+
{
38+
var factory = new ProxyFactory();
39+
var c = (MyClass)factory.CreateProxy(typeof(MyClass), new PassThroughInterceptor(new MyClass()), null);
40+
c.MethodWithConstructorConstraint<MyClass>().Should().Not.Be.Null();
41+
}
42+
43+
[Test]
44+
public void CanProxyGenericMethodWithInterfaceConstraint()
45+
{
46+
var factory = new ProxyFactory();
47+
var c = (MyClass)factory.CreateProxy(typeof(MyClass), new PassThroughInterceptor(new MyClass()), null);
48+
c.MethodWithInterfaceConstraint<IMyInterface>().Should().Be(typeof(IMyInterface));
49+
}
50+
51+
[Test]
52+
public void CanProxyGenericMethodWithReferenceTypeAndInterfaceConstraint()
53+
{
54+
var factory = new ProxyFactory();
55+
var c = (MyClass)factory.CreateProxy(typeof(MyClass), new PassThroughInterceptor(new MyDerivedClass()), null);
56+
c.MethodWithReferenceTypeAndInterfaceConstraint<MyDerivedClass>().Should().Not.Be.Null();
57+
}
58+
59+
class MyDerivedClass : MyClass, IMyInterface
60+
{ }
4761
}
4862
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace NHibernate.Test.DynamicProxyTests.GenericMethodsTests
2+
{
3+
public interface IMyGenericInterface<TId>
4+
{
5+
}
6+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace NHibernate.Test.DynamicProxyTests.GenericMethodsTests
2+
{
3+
public interface IMyInterface
4+
{
5+
}
6+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
namespace NHibernate.Test.DynamicProxyTests.GenericMethodsTests
2+
{
3+
public class MyClass
4+
{
5+
public virtual object BasicGenericMethod<T>()
6+
{
7+
if (typeof(T) == typeof(int))
8+
return 5;
9+
10+
if (typeof(T) == typeof(string))
11+
return "blha";
12+
13+
return default(T);
14+
}
15+
16+
public virtual object MethodWithGenericBaseClassConstraint<T, TY>() where T : MyGenericClass<TY>
17+
{
18+
return typeof(T);
19+
}
20+
21+
public virtual object MethodWithInterfaceConstraint<T>() where T : IMyInterface
22+
{
23+
return typeof(T);
24+
}
25+
26+
public virtual TRequestedType As<TRequestedType>() where TRequestedType : MyClass
27+
{
28+
return this as TRequestedType;
29+
}
30+
31+
public virtual TRequestedType MethodWithConstructorConstraint<TRequestedType>() where TRequestedType : new()
32+
{
33+
return new TRequestedType();
34+
}
35+
36+
public virtual TRequestedType MethodWithReferenceTypeAndInterfaceConstraint<TRequestedType>() where TRequestedType : class, IMyInterface
37+
{
38+
return this as TRequestedType;
39+
}
40+
}
41+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace NHibernate.Test.DynamicProxyTests.GenericMethodsTests
2+
{
3+
public class MyGenericClass<TId> : IMyGenericInterface<TId>
4+
{
5+
public virtual TRequestedType As<TRequestedType>() where TRequestedType : MyGenericClass<TId>
6+
{
7+
return this as TRequestedType;
8+
}
9+
10+
public virtual TRequestedType AsInterface<TRequestedType>() where TRequestedType : class, IMyGenericInterface<TId>
11+
{
12+
return this as TRequestedType;
13+
}
14+
}
15+
}

src/NHibernate.Test/NHibernate.Test.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,10 @@
226226
<Compile Include="DriverTest\Sql2008DateTime2Test.cs" />
227227
<Compile Include="DriverTest\SqlClientDriverFixture.cs" />
228228
<Compile Include="DriverTest\SqlServerCeDriverFixture.cs" />
229+
<Compile Include="DynamicProxyTests\GenericMethodsTests\IMyGenericInterface.cs" />
230+
<Compile Include="DynamicProxyTests\GenericMethodsTests\IMyInterface.cs" />
231+
<Compile Include="DynamicProxyTests\GenericMethodsTests\MyClass.cs" />
232+
<Compile Include="DynamicProxyTests\GenericMethodsTests\MyGenericClass.cs" />
229233
<Compile Include="DynamicProxyTests\PeVerifyFixture.cs" />
230234
<Compile Include="DynamicProxyTests\GenericMethodsTests\GenericMethodShouldBeProxied.cs" />
231235
<Compile Include="DynamicProxyTests\InterfaceProxySerializationTests\IMyProxy.cs" />

src/NHibernate/Proxy/DynamicProxy/DefaultProxyMethodBuilder.cs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace NHibernate.Proxy.DynamicProxy
1717
{
1818
internal class DefaultyProxyMethodBuilder : IProxyMethodBuilder
1919
{
20-
public DefaultyProxyMethodBuilder() : this(new DefaultMethodEmitter()) {}
20+
public DefaultyProxyMethodBuilder() : this(new DefaultMethodEmitter()) { }
2121

2222
public DefaultyProxyMethodBuilder(IMethodBodyEmitter emitter)
2323
{
@@ -43,8 +43,8 @@ public void CreateProxiedMethod(FieldInfo field, MethodInfo method, TypeBuilder
4343
ParameterInfo[] parameters = method.GetParameters();
4444

4545
MethodBuilder methodBuilder = typeBuilder.DefineMethod(method.Name, methodAttributes,
46-
CallingConventions.HasThis, method.ReturnType,
47-
parameters.Select(param => param.ParameterType).ToArray());
46+
CallingConventions.HasThis, method.ReturnType,
47+
parameters.Select(param => param.ParameterType).ToArray());
4848

4949
System.Type[] typeArgs = method.GetGenericArguments();
5050

@@ -61,10 +61,21 @@ public void CreateProxiedMethod(FieldInfo field, MethodInfo method, TypeBuilder
6161

6262
for (int index = 0; index < typeArgs.Length; index++)
6363
{
64-
typeArgsBuilder[index].SetInterfaceConstraints(typeArgs[index].GetGenericParameterConstraints());
64+
// Copy generic parameter attributes (Covariant, Contravariant, ReferenceTypeConstraint,
65+
// NotNullableValueTypeConstraint, DefaultConstructorConstraint).
66+
typeArgsBuilder[index].SetGenericParameterAttributes(typeArgs[index].GenericParameterAttributes);
67+
68+
// Copy generic parameter constraints (class and interfaces).
69+
var typeConstraints = typeArgs[index].GetGenericParameterConstraints();
70+
71+
var baseTypeConstraint = typeConstraints.SingleOrDefault(x => x.IsClass);
72+
typeArgsBuilder[index].SetBaseTypeConstraint(baseTypeConstraint);
73+
74+
var interfaceTypeConstraints = typeConstraints.Where(x => !x.IsClass).ToArray();
75+
typeArgsBuilder[index].SetInterfaceConstraints(interfaceTypeConstraints);
6576
}
6677
}
67-
78+
6879

6980
Debug.Assert(MethodBodyEmitter != null);
7081
MethodBodyEmitter.EmitMethodBody(methodBuilder, method, field);

0 commit comments

Comments
 (0)