Skip to content

Commit 53154a7

Browse files
committed
GH-1881 - Fix interface method attributes when generating proxies
1 parent baee90e commit 53154a7

File tree

4 files changed

+54
-4
lines changed

4 files changed

+54
-4
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using System;
2+
using System.Linq;
3+
using System.Reflection;
4+
using NHibernate.Collection;
5+
using NHibernate.Collection.Generic;
6+
using NHibernate.Proxy.DynamicProxy;
7+
using NUnit.Framework;
8+
9+
namespace NHibernate.Test.NHSpecificTest.GH1881
10+
{
11+
[TestFixture]
12+
[Obsolete]
13+
public class TestFixture
14+
{
15+
[Test]
16+
public void InterfacesShouldBeImplementedExplicitlyOnProxies()
17+
{
18+
var proxy = new ProxyFactory().CreateProxy(typeof(PersistentGenericBag<object>), null, typeof(ILazyInitializedCollection));
19+
Assert.That(proxy, Is.Not.Null);
20+
21+
foreach (var method in proxy.GetType().GetMethods().Where(m => m.DeclaringType == typeof(ILazyInitializedCollection)))
22+
{
23+
// These attributes are what .NET uses for explicitly implemented interface methods
24+
Assert.That(method.Attributes, Is.EqualTo(MethodAttributes.Private |
25+
MethodAttributes.Final |
26+
MethodAttributes.Virtual |
27+
MethodAttributes.HideBySig |
28+
MethodAttributes.NewSlot |
29+
MethodAttributes.SpecialName));
30+
}
31+
}
32+
}
33+
}

src/NHibernate/Proxy/DynamicProxy/ProxyFactory.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,13 +118,13 @@ private TypeInfo CreateUncachedProxyType(System.Type baseType, IReadOnlyCollecti
118118

119119
// Provide a custom implementation of ISerializable
120120
// instead of redirecting it back to the interceptor
121-
foreach (MethodInfo method in ProxyBuilderHelper.GetProxiableMethods(baseType, interfaces).Where(method => method.DeclaringType != typeof(ISerializable)))
121+
foreach (MethodInfo method in ProxyBuilderHelper.GetProxiableMethods(parentType, interfaces).Where(method => method.DeclaringType != typeof(ISerializable)))
122122
{
123123
ProxyMethodBuilder.CreateProxiedMethod(interceptorField, method, typeBuilder);
124124
}
125125

126126
// Make the proxy serializable
127-
AddSerializationSupport(baseType, baseInterfaces, typeBuilder, interceptorField, defaultConstructor);
127+
AddSerializationSupport(parentType, baseInterfaces, typeBuilder, interceptorField, defaultConstructor);
128128
TypeInfo proxyType = typeBuilder.CreateTypeInfo();
129129

130130
ProxyAssemblyBuilder.Save(assemblyBuilder);

src/NHibernate/Proxy/NHibernateProxyBuilder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ private static void EmitCallBaseIfLazyInitializerIsNull(
394394
IL.Emit(OpCodes.Bne_Un, skipBaseCall);
395395

396396
IL.Emit(OpCodes.Ldarg_0);
397-
EmitCallMethod(IL, OpCodes.Call, method);
397+
EmitCallMethod(IL, method.DeclaringType.IsInterface ? OpCodes.Callvirt : OpCodes.Call, method);
398398
IL.Emit(OpCodes.Ret);
399399

400400
IL.MarkLabel(skipBaseCall);

src/NHibernate/Proxy/ProxyBuilderHelper.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,24 @@ internal static MethodBuilder GetObjectDataMethodBuilder(TypeBuilder typeBuilder
137137
internal static MethodBuilder GenerateMethodSignature(string name, MethodInfo method, TypeBuilder typeBuilder)
138138
{
139139
//TODO: Should we use attributes of base method?
140-
var methodAttributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual;
140+
MethodAttributes methodAttributes;
141+
if (method.DeclaringType.IsInterface)
142+
{
143+
// These are the attributes used for an explicit interface method implementation in .NET.
144+
methodAttributes =
145+
MethodAttributes.Private |
146+
MethodAttributes.Final |
147+
MethodAttributes.Virtual |
148+
MethodAttributes.HideBySig |
149+
MethodAttributes.NewSlot |
150+
MethodAttributes.SpecialName;
151+
// .NET uses an expanded name for explicit interface implementation methods.
152+
name = typeBuilder.FullName + "." + method.DeclaringType.FullName + "." + name;
153+
}
154+
else
155+
{
156+
methodAttributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual;
157+
}
141158

142159
if (method.IsSpecialName)
143160
methodAttributes |= MethodAttributes.SpecialName;

0 commit comments

Comments
 (0)