Skip to content

[duplicate-code] Duplicate Code: TypeForwardedTo Assembly Attribute Pattern #8594

@Evangelink

Description

@Evangelink

🔍 Duplicate Code Detected: TypeForwardedTo Assembly Attribute Pattern

Analysis of commit ed7ecb2

Summary

The #else blocks in polyfill files contain repetitive TypeForwardedTo assembly attribute declarations. This pattern appears in 16+ files with identical structure but different type parameters. Each file forwards its polyfill type to the framework's built-in implementation when targeting .NET Core or later.

Duplication Details

Pattern: Conditional TypeForwardedTo Declarations

  • Severity: Medium-High

  • Occurrences: 16+ files with 30+ individual type forwarding declarations

  • Total Duplicate Lines: ~50+ lines

  • Locations:

    • src/Polyfills/CallerArgumentExpressionAttribute.cs (line 34: [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.CompilerServices.CallerArgumentExpressionAttribute))])
    • src/Polyfills/CompilerFeatureRequiredAttribute.cs (line 49: [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute))])
    • src/Polyfills/ExperimentalAttribute.cs (line 54: [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.ExperimentalAttribute))])
    • src/Polyfills/IsExternalInit.cs (line 19: [assembly: TypeForwardedTo(typeof(IsExternalInit))])
    • src/Polyfills/ModuleInitializerAttribute.cs (line 23: [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.CompilerServices.ModuleInitializerAttribute))])
    • src/Polyfills/RequiredMemberAttribute.cs (line 25: [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.CompilerServices.RequiredMemberAttribute))])
    • src/Polyfills/NullableAttribtues.cs (lines 160-171: 11 separate TypeForwardedTo declarations)
    • src/Polyfills/PlatformAttributes.cs (lines 195-202: 7 separate TypeForwardedTo declarations)
    • Plus 8+ more files
  • Code Sample:

// Pattern repeated in every polyfill file:
#if !NETCOREAPP

// ... polyfill implementation ...

#else
[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.CompilerServices.SomeAttribute))]
#endif

Additional Context:

  • When targeting .NET Core or later (#if ... #else branch), the polyfill types are not needed because the framework provides them natively
  • The TypeForwardedTo attribute tells the compiler to redirect references to the framework's implementation
  • This is a .NET compiler convention for multi-targeting scenarios
  • The pattern is consistent but requires manual duplication for each polyfill type

Variations in the Pattern:

  • Some files use fully-qualified System.Runtime.CompilerServices.TypeForwardedTo
  • Others use just TypeForwardedTo (relying on using directives)
  • IsExternalInit.cs uses the short form while others use the long form

Impact Analysis

  • Maintainability: If the conditional compilation strategy changes (e.g., targeting .NET 5+ instead of NETCOREAPP), all 16+ files must be updated.
  • Bug Risk:
    • Forgetting the TypeForwardedTo on a new polyfill causes runtime type resolution errors when targeting newer frameworks
    • Inconsistent namespace qualification (fully-qualified vs. short form) can cause confusion
    • Copy-paste errors where the wrong type is forwarded
  • Code Bloat: ~50 lines of repetitive conditional blocks
  • Consistency: No automated verification that the forwarded type matches the polyfill type being defined

Refactoring Recommendations

1. MSBuild Target to Generate TypeForwardedTo (Recommended)

  • Create an MSBuild target that scans polyfill files and generates a single PolyfillForwarders.g.cs file
  • Target extracts type names from polyfill files and emits corresponding TypeForwardedTo attributes
  • Remove manual #else blocks from all polyfill files
  • Estimated effort: 6-8 hours
  • Benefits:
    • Single generated file contains all forwarders
    • Impossible to have type mismatch (type name is extracted from source)
    • Consistent formatting and qualification
    • Easy to update conditional compilation logic globally
  • Implementation Sketch:
    <Target Name="GeneratePolyfillForwarders" BeforeTargets="CoreCompile">
      <ItemGroup>
        <PolyfillFiles Include="$(MSBuildThisFileDirectory)Polyfills\*.cs" />
      </ItemGroup>
      <!-- Parse files, extract types, generate PolyfillForwarders.g.cs -->
    </Target>

2. Source Generator for TypeForwardedTo Injection

  • Create a Roslyn source generator that emits TypeForwardedTo attributes at compile time
  • Generator scans polyfill types and generates forwarding attributes automatically
  • Estimated effort: 8-10 hours
  • Benefits:
    • Fully automated
    • Type-safe (uses Roslyn's type information)
    • Works seamlessly with IDE
  • Trade-offs:
    • More complex than MSBuild approach
    • Requires source generator expertise

3. T4 Template Approach

  • If polyfill files are generated from T4 templates (as recommended in issue [duplicate-code] Duplicate Code: Polyfill File Structure Boilerplate #8591), include the TypeForwardedTo logic in the template
  • Estimated effort: 2-3 hours (if T4 approach is already implemented)
  • Benefits:
    • Consistent with overall polyfill generation strategy
    • Single template maintains both implementation and forwarding
  • Limitations:
    • Requires T4 template infrastructure

4. Centralized Forwarding File

  • Manually create a single PolyfillForwarders.cs file with all TypeForwardedTo attributes
  • Remove them from individual polyfill files
  • Update the file when adding new polyfills
  • Estimated effort: 2-3 hours
  • Benefits:
    • Simple to implement
    • All forwarders in one place
  • Limitations:
    • Still manual
    • Requires discipline to update when adding polyfills
    • No automatic type matching verification

Implementation Checklist

  • Review options with team
  • Decide on approach (MSBuild target vs. source generator vs. T4 vs. manual)
  • If MSBuild target approach:
    • Create MSBuild target to parse polyfill types
    • Generate PolyfillForwarders.g.cs
    • Test with all target frameworks
    • Remove #else blocks from polyfill files
  • If source generator approach:
    • Create generator project
    • Implement type scanning and forwarding logic
    • Test with all target frameworks
    • Remove #else blocks from polyfill files
  • Verify multi-targeting scenarios work correctly
  • Update documentation for adding new polyfills
  • Consider combining with issue [duplicate-code] Duplicate Code: Polyfill File Structure Boilerplate #8591 solution

Related Issues

Analysis Metadata

  • Analyzed Files: 48 C# source files
  • Detection Method: Semantic code analysis with pattern matching
  • Commit: ed7ecb2
  • Analysis Date: 2026-05-26T05:35:57Z
  • Repository: microsoft/testfx

Generated by Duplicate Code Detector · ● 1.5M ·

Add this agentic workflows to your repo

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/duplicate-code-detector.md@main
  • expires on May 28, 2026, 5:44 AM UTC

Metadata

Metadata

Labels

type/automationCreated or maintained by an agentic workflow.type/tech-debtCode health, refactoring, simplification.

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions