|
5 | 5 |
|
6 | 6 | namespace Kampute.DocToolkit.Metadata.Adapters |
7 | 7 | { |
| 8 | + using Kampute.DocToolkit.Support; |
8 | 9 | using System; |
9 | 10 | using System.Collections.Generic; |
10 | 11 | using System.Linq; |
@@ -184,7 +185,7 @@ protected virtual IEnumerable<IOperator> GetOperators() => Reflection |
184 | 185 | /// <returns>An enumeration of <see cref="IMethod"/> objects representing the explicit interface methods implemented by the type.</returns> |
185 | 186 | protected virtual IEnumerable<IMethod> GetExplicitInterfaceMethods() => Reflection |
186 | 187 | .GetMethods(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Instance) |
187 | | - .Where(m => !m.IsSpecialName && IsExplicitMember(m)) |
| 188 | + .Where(m => !m.IsSpecialName && IsExplicitMethod(m)) |
188 | 189 | .Select(Assembly.Repository.GetMethodMetadata<IMethod>) |
189 | 190 | .OrderBy(m => m.Name, StringComparer.Ordinal) |
190 | 191 | .ThenBy(m => m.Parameters.Count); |
@@ -249,13 +250,46 @@ protected virtual bool IsVisibleNestedType(Type type) |
249 | 250 | /// <summary> |
250 | 251 | /// Determines whether a member is an explicit interface implementation. |
251 | 252 | /// </summary> |
252 | | - /// <param name="member">The member to check.</param> |
| 253 | + /// <param name="member">The reflection information of the member to check.</param> |
253 | 254 | /// <returns><see langword="true"/> if the member is an explicit interface implementation; otherwise, <see langword="false"/>.</returns> |
254 | 255 | protected virtual bool IsExplicitMember(MemberInfo member) |
255 | 256 | { |
256 | 257 | return member is not null |
257 | 258 | && member.Name.IndexOf('.') > 0 |
258 | 259 | && !member.CustomAttributes.Any(attr => attr.AttributeType.FullName == "System.Runtime.CompilerServices.CompilerGeneratedAttribute"); |
259 | 260 | } |
| 261 | + |
| 262 | + /// <summary> |
| 263 | + /// Determines whether a method is an explicit interface implementation. |
| 264 | + /// </summary> |
| 265 | + /// <param name="method">The reflection information of the method to check.</param> |
| 266 | + /// <returns><see langword="true"/> if the method is an explicit interface implementation; otherwise, <see langword="false"/>.</returns> |
| 267 | + /// <remarks> |
| 268 | + /// This method excludes compiler-generated bridge methods for implicit interface implementations with by-ref parameters. |
| 269 | + /// </remarks> |
| 270 | + protected virtual bool IsExplicitMethod(MethodInfo method) |
| 271 | + { |
| 272 | + if (!IsExplicitMember(method) || !(method.IsPrivate && method.IsFinal && method.IsVirtual)) |
| 273 | + return false; |
| 274 | + |
| 275 | + // Compiler-generated bridge methods are created for implicit interface implementations |
| 276 | + // that have by-ref parameters (in, ref, out). Check if any parameter is by-ref. |
| 277 | + var parameters = method.GetParameters(); |
| 278 | + if (!parameters.Any(p => p.ParameterType.IsByRef)) |
| 279 | + return true; // No by-ref parameters, so it's a user-written explicit implementation |
| 280 | + |
| 281 | + // Has by-ref parameters - check if there's a public method with the same signature |
| 282 | + var publicMethod = Reflection.GetMethod |
| 283 | + ( |
| 284 | + name: method.Name.SubstringAfterLast('.'), |
| 285 | + bindingAttr: BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance, |
| 286 | + binder: null, |
| 287 | + types: [.. parameters.Select(p => p.ParameterType)], |
| 288 | + modifiers: null |
| 289 | + ); |
| 290 | + |
| 291 | + // If a public method with the same signature exists, this is a compiler-generated bridge |
| 292 | + return publicMethod is null; |
| 293 | + } |
260 | 294 | } |
261 | 295 | } |
0 commit comments