Skip to content

Linker shouldn't warn when using new() generic constraints #1412

@eerhardt

Description

@eerhardt

Using the following csproj and code

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5.0</TargetFramework>
    <PublishTrimmed>true</PublishTrimmed>
    <TrimMode>link</TrimMode>
    <_ExtraTrimmerArgs>--verbose</_ExtraTrimmerArgs>
  </PropertyGroup>

  <Target Name="EnsureAllAssembliesAreLinked"
          BeforeTargets="PrepareForILLink"> 
    <ItemGroup>
      <ManagedAssemblyToLink>
        <TrimMode>link</TrimMode>
      </ManagedAssemblyToLink>
      <TrimmerRootAssembly Include="@(IntermediateAssembly)" />
    </ItemGroup>
  </Target>
</Project>
using System;

class Program
{
    static int Main(string[] args)
    {
        Add((OptionsA a) => Console.Write(a));

        return 100;
    }

    private class OptionsA
    {
    }

    private static void Add<TSource>(Action<TSource> configureSource) where TSource : new()
    {
        var source = new TSource();
        configureSource?.Invoke(source);
    }
}
  1. Using the latest .NET 5 SDK
  2. dotnet publish -r win-x64

You get a warning like the following:

F:\DotNetTest\HelloWorld\Program.cs(17,5): Trim analysis warning IL2006: .Program.Add<TSource>(Action<TSource>): The generic parameter 'TSource' from '.Program.Add<TSource>(Action<TSource>)' with dynamically accessed member kinds 'None' is passed into the generic parameter 'T' from 'System.Activator.CreateInstance<T>()' which requires dynamically accessed member kinds 'PublicParameterlessConstructor'. To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicParameterlessConstructor'. [F:\DotNetTest\HelloWorld\HelloWorld.csproj]

This is because the above pattern of where TSource : new() and then calling new TSource(); in code turns into:

    private static void Add<TSource>(Action<TSource> configureSource)
    where TSource : new()
    {
        TSource tSource = Activator.CreateInstance<TSource>();
        if (configureSource != null)
        {
            configureSource(tSource);
        }
    }

And the linker sees Activator.CreateInstance<TSource>() but it doesn't see a PublicParameterlessConstructor usage.

cc @marek-safar @sbomer @MichalStrehovsky @vitek-karas

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions