-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
IsExternalInit must be declared for all TFMs #5
Comments
@AArnott @manuelroemer If I'm creating some library that I want to be able to run in older TFMs and still use <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard1.3;net5.0</TargetFrameworks>
<LangVersion>9</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="IsExternalInit" Version="1.0.0" Condition=" '$(TargetFramework)' == 'netstandard1.3' ">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project> This is very similar to using |
@gravity00 async/await in .NET Framework 4.0 brought in a runtime dependency, which helps the case that you should drop it in later frameworks. It also didn't (AFAIK) impact your public API since
This is why I (still) strongly recommend that if you use this package, you forever consider yourself "stuck" using it, for all TFMs and for all time. Not that I have any qualms with that. It's an empty attribute in your dll, and for most purposes can be internal. A small price to pay to avoid a very confusing breaking change. |
@AArnott just to be sure I do understand the racional with some practical use case, lets consider conditional references:
I can see the point and you are correct! I'm very careful to ensure my libs also compile for the different TFMs the libs I depend on compile (in this example the problem would be prevented if |
@gravity00 LibraryB and LibraryC should not depend on IsExternalInit, even transitively. LibraryA's dependency on IsExternalInit should be done with |
Despite way too much time having passed since the creation of this issue, it should now be fixed with version 1.0.1 on NuGet. I tested the newest version using a local package feed before uploading to NuGet and everything seems to work fine, but please let me know if there is any regression. I'm not primarily working with .NET at the moment, so I might not realize myself. Thanks! |
Never said it would depend on
But we are both agreeing in your point. |
Actually they wont receive the internal copy for usage unless one provides |
The C# compiler team has informed me that this attribute being internal is actually problematic. But making it public comes with trouble of its own. A future version of the compiler will be made smarter so that in the face of multiple definitions of this attribute, the one from the local project, or the one from the authoritative reference assembly, will be used. |
@AArnott I think a better option would be to have the compiler emit the attribute itself until then then it would make this package or manually making the attribute internal ourselves unneeded. |
Yes, and for many new attributes this is exactly what the compiler does. I suspect the reason they didn't in this case is that the assembly-identity of the attribute is important to the runtime. If they ever emitted it, they would have to always emit it. I don't know why they didn't make that choice. |
@AArnott do you have a public source of that comment by chance? FWIW, the R# team recommends making this |
I prefer it to be public so that way for example I could have a dummy project that brings in all the attributes at runtime that are normally internal in the regular runtime (dotnet/runtime) in there, then I could just reference that for that way I could use all the newer language features in those older projects if needed (like in roslyn source generators for example perhaps). |
I just hit this now. This is one of the things I hate about .NET Runtime. This also stems from the root cause of needing to maintain compatibility that you have several intricate and unsolvable problems in the Runtime. Just break things across major versions. We now have Analyzers, Fixers and Source Generators to help us migrate. |
Unlike other polyfill packages where you can get away with declaring attributes only where the TFM does not declare them,
IsExternalInit
must be declared in the same assembly forever and for all TFMs or else it's a binary breaking change.I see in your nuspec that you omit the declaration for net5 but you can't do that. You must declare it there as well.
The reason being the compiler generates metadata on the
init
property accessors that references this attribute using its assembly-qualified type name. When other assemblies reference this one and invoke aninit
accessor, the compiler embeds that exact same assembly-qualified reference into their invocation of that accessor. Now imagine this referencing library runs in a process where the referenced library is no longer the one that targeted net472 but targets net5. The CLR will throw a MissingMethodException when it encounters the init accessor because the attribute on the accessor does not match the IsExternalInit reference in the caller.See proof of the breaking change
The text was updated successfully, but these errors were encountered: