Skip to content

Provide a WholeProjectDecompiler constructor with no default parameter values#3903

Open
ds5678 wants to merge 1 commit into
icsharpcode:masterfrom
ds5678:iassemblyreferenceclassifier
Open

Provide a WholeProjectDecompiler constructor with no default parameter values#3903
ds5678 wants to merge 1 commit into
icsharpcode:masterfrom
ds5678:iassemblyreferenceclassifier

Conversation

@ds5678

@ds5678 ds5678 commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Problem

I'm trying to trim types from my application, and I'm having issues with the NativeAOT compiler not realizing that my parameters are never null.

AssemblyReferenceClassifier = assemblyReferenceClassifier ?? new AssemblyReferenceClassifier();

this.projectWriter = projectWriter ?? (Settings.UseSdkStyleProjectFormat ? ProjectFileWriterSdkStyle.Create() : ProjectFileWriterDefault.Create());

Solution

  • I created an interface IAssemblyReferenceClassifier and replaced most uses of AssemblyReferenceClassifier with it.
  • I moved default initialization from the most specific WholeProjectDecompiler constructor to the second most one.
  • I added ArgumentNullException checks to the most specific WholeProjectDecompiler constructor.

{
}

protected WholeProjectDecompiler(

@siegfriedpammer siegfriedpammer Jul 22, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't this a compile-time silent breaking change, since now anyone deriving from WholeProjectDecompiler using the protected ctor, will get exceptions in their face, if they relied on the default initialization of AssemblyReferenceClassifier and projectWriter?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not really sure how nullable annotations work for the repository (because of the reference assembly annotation package), but ideally it would go from maybe-null to not-null, so any callers who provide a maybe-null argument will get a warning at compile time.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the reference annotator package just copies all the annotations from a given reference framework to the target framework of the decompiler (netstandard2.0) at build-time so Roslyn sees the annotated variants when compiling the decompiler project.

The only issue is that we haven't really invested in annotating everything and there's multiple reasons:

  • It's a ton of work
  • The old AST model used a null object pattern, making NRT somewhat useless
  • Most transforms use a dataflow pattern, that's not really NRT friendly: fields are set in Run and are effectively non-null for the entire duration of the transform (and therefore safe), but this cannot be expressed nicely just by sprinkling ? and some extra attributes.

Given that the new AST model actively uses NRT, it might be worth asking Claude to try to annotate everything.

But as it stands now this is a somewhat ugly breaking change, also third-party users have no way of instantiating the project writer and classifier defaults, afaik...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But as it stands now this is a somewhat ugly breaking change

I tried to make it as minimally breaking as possible, but I suspected that this might be the answer.

third-party users have no way of instantiating the project writer and classifier defaults, afaik...

The classifier is public, but yes the project writers are internal. Is it intended for them to be an implementation detail?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we could make the project writer API public too... git history of the whole feature shows that all the other parts have been made public already. So... are we fine with just public or do we unseal at the same time?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are we fine with just public or do we unseal at the same time?

I'm leaning towards not unsealing because that involves decisions about what the API should be. However, one of my implementations involved a fair bit of copy-pasting. Do you think it would benefit from inheritance?

https://github.com/AssetRipper/AssetRipper/blob/0730de9853007bf255363cb68eadb05e11cf10a3/Source/AssetRipper.Export.PrimaryContent/Scripts/ProjectFileWriter.cs

I have another implementation for IProjectFileWriter. Do you think it should be included upstream?

https://github.com/AssetRipper/AssetRipper/blob/0730de9853007bf255363cb68eadb05e11cf10a3/Source/AssetRipper.Export/Scripts/NullProjectFileWriter.cs

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WriteFrameworkInfo sounds like a strong candidate for an extensibility point...

Ideas:

  • virtual void WriteCustomPropertyGroup(XmlTextWriter xml, ...); which allows adding one more PropertyGroup. And we'd probably need the same a custom ItemGroup?
  • maybe model properties and items using an object model that is then serialized to XML

I think the template method approach might be sufficient... might be a bit weird, if we want to avoid <PropertyGroup></PropertyGroup> if the method is not overridden.

Do you have a better idea perhaps?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants