Skip to content

Commit a98192d

Browse files
authored
Make object destructors not proxiable (#3233)
Fixes #3205
1 parent 160e35d commit a98192d

File tree

3 files changed

+131
-9
lines changed

3 files changed

+131
-9
lines changed

src/NHibernate.Test/NHSpecificTest/ProxyValidator/ShouldBeProxiableTests.cs

Lines changed: 114 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,27 @@ namespace NHibernate.Test.NHSpecificTest.ProxyValidator
88
[TestFixture]
99
public class ShouldBeProxiableTests
1010
{
11-
private class MyClass: IDisposable
11+
private class MyClass : IDisposable
1212
{
1313
public void Dispose()
1414
{
1515
}
16+
17+
~MyClass()
18+
{
19+
}
20+
21+
// ReSharper disable once InconsistentNaming
22+
// This is intentionally lower case
23+
public virtual void finalize()
24+
{
25+
}
26+
27+
public virtual void Finalize(int a)
28+
{
29+
}
1630
}
31+
1732
private class ProtectedNoVirtualProperty
1833
{
1934
protected int Aprop { get; set; }
@@ -44,6 +59,104 @@ public void DisposeNotBeProxiable()
4459
Assert.That(method.ShouldBeProxiable(), Is.False);
4560
}
4661

62+
[Test]
63+
public void ObjectDestructorShouldNotBeProxiable()
64+
{
65+
var method = typeof(object).GetMethod(
66+
"Finalize",
67+
BindingFlags.NonPublic | BindingFlags.Instance);
68+
69+
Assert.That(method.ShouldBeProxiable(), Is.False);
70+
}
71+
72+
[Test]
73+
public void ObjectDestructorIsNotProxiable()
74+
{
75+
var method = typeof(object).GetMethod(
76+
"Finalize",
77+
BindingFlags.NonPublic | BindingFlags.Instance);
78+
79+
Assert.That(method.IsProxiable(), Is.False);
80+
}
81+
82+
[Test]
83+
public void MyClassDestructorShouldNotBeProxiable()
84+
{
85+
var method = typeof(MyClass).GetMethod(
86+
"Finalize",
87+
BindingFlags.NonPublic | BindingFlags.Instance,
88+
null,
89+
System.Type.EmptyTypes,
90+
null);
91+
92+
Assert.That(method.ShouldBeProxiable(), Is.False);
93+
}
94+
95+
[Test]
96+
public void MyClassDestructorIsNotProxiable()
97+
{
98+
var method = typeof(MyClass).GetMethod(
99+
"Finalize",
100+
BindingFlags.NonPublic | BindingFlags.Instance,
101+
null,
102+
System.Type.EmptyTypes,
103+
null);
104+
105+
Assert.That(method.IsProxiable(), Is.False);
106+
}
107+
108+
[Test]
109+
public void MyClassLowerCaseFinalizeShouldBeProxiable()
110+
{
111+
var method = typeof(MyClass).GetMethod(
112+
"finalize",
113+
BindingFlags.Public | BindingFlags.Instance,
114+
null,
115+
System.Type.EmptyTypes,
116+
null);
117+
118+
Assert.That(method.ShouldBeProxiable(), Is.True);
119+
}
120+
121+
[Test]
122+
public void MyClassLowerCaseFinalizeIsProxiable()
123+
{
124+
var method = typeof(MyClass).GetMethod(
125+
"finalize",
126+
BindingFlags.Public | BindingFlags.Instance,
127+
null,
128+
System.Type.EmptyTypes,
129+
null);
130+
131+
Assert.That(method.IsProxiable(), Is.True);
132+
}
133+
134+
[Test]
135+
public void MyClassFinalizeWithParametersShouldBeProxiable()
136+
{
137+
var method = typeof(MyClass).GetMethod(
138+
"Finalize",
139+
BindingFlags.Public | BindingFlags.Instance,
140+
null,
141+
new[] { typeof(int) },
142+
null);
143+
144+
Assert.That(method.ShouldBeProxiable(), Is.True);
145+
}
146+
147+
[Test]
148+
public void MyClassFinalizeWithParametersIsProxiable()
149+
{
150+
var method = typeof(MyClass).GetMethod(
151+
"Finalize",
152+
BindingFlags.Public | BindingFlags.Instance,
153+
null,
154+
new[] { typeof(int) },
155+
null);
156+
157+
Assert.That(method.IsProxiable(), Is.True);
158+
}
159+
47160
[Test]
48161
public void WhenProtectedNoVirtualPropertyThenShouldntBeProxiable()
49162
{

src/NHibernate/Proxy/DefaultDynamicProxyMethodCheckerExtensions.cs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public static bool IsProxiable(this MethodInfo method)
1111
{
1212
return !method.IsFinal
1313
&& (method.DeclaringType != typeof(MarshalByRefObject))
14-
&& (method.DeclaringType != typeof(object) || !"finalize".Equals(method.Name, StringComparison.OrdinalIgnoreCase))
14+
&& !IsFinalizeMethod(method)
1515
&&
1616
(
1717
((method.IsPublic || method.IsFamily) && (method.IsVirtual || method.IsAbstract)) // public or protected (virtual)
@@ -24,7 +24,7 @@ public static bool ShouldBeProxiable(this MethodInfo method)
2424
{
2525
// to use only for real methods (no getter/setter)
2626
return (method.DeclaringType != typeof (MarshalByRefObject)) &&
27-
(method.DeclaringType != typeof (object) || !"finalize".Equals(method.Name, StringComparison.OrdinalIgnoreCase)) &&
27+
!IsFinalizeMethod(method) &&
2828
(!(method.DeclaringType == typeof (object) && "GetType".Equals(method.Name))) &&
2929
(!(method.DeclaringType == typeof (object) && "obj_address".Equals(method.Name))) && // Mono-specific method
3030
!IsDisposeMethod(method) &&
@@ -33,12 +33,10 @@ public static bool ShouldBeProxiable(this MethodInfo method)
3333

3434
public static bool ShouldBeProxiable(this PropertyInfo propertyInfo)
3535
{
36-
if(propertyInfo != null)
37-
{
38-
var accessors = propertyInfo.GetAccessors(true);
39-
return accessors.Where(x => x.IsPublic || x.IsAssembly || x.IsFamilyOrAssembly).Any();
40-
}
41-
return true;
36+
if (propertyInfo == null) return true;
37+
38+
var accessors = propertyInfo.GetAccessors(true);
39+
return accessors.Any(x => x.IsPublic || x.IsAssembly || x.IsFamilyOrAssembly);
4240
}
4341

4442
private static bool IsDisposeMethod(MethodInfo method)
@@ -47,5 +45,10 @@ private static bool IsDisposeMethod(MethodInfo method)
4745
return method.Name.Equals("Dispose") && method.MemberType == MemberTypes.Method && method.GetParameters().Length == 0;
4846
// return method.Name.Equals("Dispose") && method.IsMethodOf(typeof(IDisposable));
4947
}
48+
49+
private static bool IsFinalizeMethod(MethodInfo method)
50+
{
51+
return method.GetBaseDefinition() == ReflectionCache.ObjectMethods.Finalize;
52+
}
5053
}
5154
}

src/NHibernate/Util/ReflectionCache.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,5 +232,11 @@ internal static class TypeMethods
232232
internal static readonly MethodInfo GetTypeFromHandle =
233233
ReflectHelper.FastGetMethod(System.Type.GetTypeFromHandle, default(RuntimeTypeHandle));
234234
}
235+
236+
internal static class ObjectMethods
237+
{
238+
internal static readonly MethodInfo Finalize =
239+
typeof(object).GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Instance);
240+
}
235241
}
236242
}

0 commit comments

Comments
 (0)