@@ -289,31 +289,40 @@ private static Type EmitType(IList<DynamicProperty> properties, bool createParam
289289 {
290290 var fieldName = properties [ i ] . Name ;
291291 var fieldType = properties [ i ] . Type ;
292- var equalityComparerT = EqualityComparer . MakeGenericType ( fieldType ) ;
292+
293+ // Use object-based equality comparer for types that are not publicly accessible from
294+ // the dynamic assembly (e.g., compiler-generated anonymous types). Calling
295+ // EqualityComparer<T>.get_Default() for a non-public T will throw MethodAccessException.
296+ var fieldTypeIsAccessible = IsTypePubliclyAccessible ( fieldType ) ;
297+ var equalityType = fieldTypeIsAccessible ? fieldType : typeof ( object ) ;
298+ var equalityComparerT = EqualityComparer . MakeGenericType ( equalityType ) ;
293299
294300 // Equals()
295301 MethodInfo equalityComparerTDefault = equalityComparerT . GetMethod ( "get_Default" , BindingFlags . Static | BindingFlags . Public ) ! ;
296- MethodInfo equalityComparerTEquals = equalityComparerT . GetMethod ( nameof ( EqualityComparer . Equals ) , BindingFlags . Instance | BindingFlags . Public , null , [ fieldType , fieldType ] , null ) ! ;
302+ MethodInfo equalityComparerTEquals = equalityComparerT . GetMethod ( nameof ( EqualityComparer . Equals ) , BindingFlags . Instance | BindingFlags . Public , null , [ equalityType , equalityType ] , null ) ! ;
297303
298304 // Illegal one-byte branch at position: 9. Requested branch was: 143.
299305 // So replace OpCodes.Brfalse_S to OpCodes.Brfalse
300306 ilgeneratorEquals . Emit ( OpCodes . Brfalse , equalsLabel ) ;
301307 ilgeneratorEquals . Emit ( OpCodes . Call , equalityComparerTDefault ) ;
302308 ilgeneratorEquals . Emit ( OpCodes . Ldarg_0 ) ;
303309 ilgeneratorEquals . Emit ( OpCodes . Ldfld , fieldBuilders [ i ] ) ;
310+ if ( ! fieldTypeIsAccessible ) ilgeneratorEquals . Emit ( OpCodes . Box , fieldType ) ;
304311 ilgeneratorEquals . Emit ( OpCodes . Ldloc_0 ) ;
305312 ilgeneratorEquals . Emit ( OpCodes . Ldfld , fieldBuilders [ i ] ) ;
313+ if ( ! fieldTypeIsAccessible ) ilgeneratorEquals . Emit ( OpCodes . Box , fieldType ) ;
306314 ilgeneratorEquals . Emit ( OpCodes . Callvirt , equalityComparerTEquals ) ;
307315
308316 // GetHashCode();
309- MethodInfo equalityComparerTGetHashCode = equalityComparerT . GetMethod ( nameof ( EqualityComparer . GetHashCode ) , BindingFlags . Instance | BindingFlags . Public , null , [ fieldType ] , null ) ! ;
317+ MethodInfo equalityComparerTGetHashCode = equalityComparerT . GetMethod ( nameof ( EqualityComparer . GetHashCode ) , BindingFlags . Instance | BindingFlags . Public , null , [ equalityType ] , null ) ! ;
310318 ilgeneratorGetHashCode . Emit ( OpCodes . Stloc_0 ) ;
311319 ilgeneratorGetHashCode . Emit ( OpCodes . Ldc_I4 , - 1521134295 ) ;
312320 ilgeneratorGetHashCode . Emit ( OpCodes . Ldloc_0 ) ;
313321 ilgeneratorGetHashCode . Emit ( OpCodes . Mul ) ;
314322 ilgeneratorGetHashCode . Emit ( OpCodes . Call , equalityComparerTDefault ) ;
315323 ilgeneratorGetHashCode . Emit ( OpCodes . Ldarg_0 ) ;
316324 ilgeneratorGetHashCode . Emit ( OpCodes . Ldfld , fieldBuilders [ i ] ) ;
325+ if ( ! fieldTypeIsAccessible ) ilgeneratorGetHashCode . Emit ( OpCodes . Box , fieldType ) ;
317326 ilgeneratorGetHashCode . Emit ( OpCodes . Callvirt , equalityComparerTGetHashCode ) ;
318327 ilgeneratorGetHashCode . Emit ( OpCodes . Add ) ;
319328
@@ -422,6 +431,32 @@ private static Type EmitType(IList<DynamicProperty> properties, bool createParam
422431 return typeBuilder . CreateType ( ) ;
423432 }
424433
434+ /// <summary>
435+ /// Determines whether a type is publicly accessible from an external (dynamic) assembly.
436+ /// Non-public types (e.g., compiler-generated anonymous types) cannot be used as generic
437+ /// type arguments in EqualityComparer<T> from a dynamic assembly without causing
438+ /// a <see cref="MethodAccessException"/> at runtime.
439+ /// </summary>
440+ private static bool IsTypePubliclyAccessible ( Type type )
441+ {
442+ // Check if the type itself is public
443+ if ( ! type . IsPublic && ! type . IsNestedPublic )
444+ {
445+ return false ;
446+ }
447+
448+ // For constructed generic types (e.g., List<MyPrivateType>),
449+ // all type arguments must also be publicly accessible.
450+ // Generic type definitions (e.g., List<>) have unbound type parameters
451+ // which are not concrete types and should not be checked.
452+ if ( type . IsGenericType && ! type . IsGenericTypeDefinition )
453+ {
454+ return type . GetGenericArguments ( ) . All ( IsTypePubliclyAccessible ) ;
455+ }
456+
457+ return true ;
458+ }
459+
425460 private static void EmitEqualityOperators ( TypeBuilder typeBuilder , MethodBuilder equals )
426461 {
427462 // Define the '==' operator
0 commit comments