Skip to content

Detect init-only properties, required members, and readonly structs/fields - #172

Merged
dennisdoomen merged 3 commits into
mainfrom
dennisdoomen-init-only-required-readonly
Aug 10, 2026
Merged

Detect init-only properties, required members, and readonly structs/fields#172
dennisdoomen merged 3 commits into
mainfrom
dennisdoomen-init-only-required-readonly

Conversation

@dennisdoomen

Copy link
Copy Markdown
Owner

Summary

Implements approved API proposal #157 by adding reflection helpers to detect C# init-only properties, required members, and readonly structs.

PropertyInfoExtensions

  • IsInitOnly() — true when the setter's return parameter has the System.Runtime.CompilerServices.IsExternalInit required custom modifier (matched by full type name for cross-assembly/TFM safety, since PolySharp may polyfill this type on older TFMs).
  • IsRequired() — true when the property is marked with the C# 11 required modifier (delegates to MemberInfoExtensions.IsRequired).
  • IsWritable() — true only when the property has a setter and is not init-only (per the issue's explicit design decision that init is not "writable").

MemberInfoExtensions

  • IsRequired(this MemberInfo member) — general-purpose check for System.Runtime.CompilerServices.RequiredMemberAttribute, matched by full name.

FieldInfoExtensions (new file)

  • IsRequired(this FieldInfo field) — same check, specific to fields.

TypeMetaDataExtensions

  • IsReadOnlyStruct() — true for structs decorated with IsReadOnlyAttribute (matched by full name).
  • IsFileLocal() — heuristic detection of C# 11 file-local types via the compiler's metadata name-mangling pattern (<...>F{64-hex-hash}__{OriginalName}), documented as heuristic (same caveat as the existing IsRecordStruct).

All attribute/modifier checks use full-name string matching rather than typeof(...) comparisons, since these BCL types may not exist on older TFMs (net47, netstandard2.0/2.1) and could instead resolve to a PolySharp-polyfilled assembly, which would break Type equality comparisons.

Tests

Added specs covering init-only vs. settable vs. get-only properties, required vs. non-required properties/fields, readonly vs. normal structs, and file-local vs. normal/anonymous types (including a file-modified fixture type).

Docs

Updated README's "How do I use it?" section to mention the new extension methods.

Validation

  • dotnet build src\Reflectify\Reflectify.csproj — succeeds for all 4 TFMs (net47, net6.0, netstandard2.0, netstandard2.1).
  • dotnet test tests\Reflectify.Specs\Reflectify.Specs.csproj -f net8.0 — 206/206 passing.
  • Verified behavior empirically against a small standalone Roslyn-compiled sample to confirm exact metadata shapes (custom modifiers, attribute placement, file-local name mangling) before implementing.

Closes #157

@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown

Test Results

    4 files  ± 0      4 suites  ±0   2m 59s ⏱️ -51s
  326 tests +19    326 ✅ +19  0 💤 ±0  0 ❌ ±0 
1 299 runs  +76  1 299 ✅ +76  0 💤 ±0  0 ❌ ±0 

Results for commit bdb8593. ± Comparison against base commit 479309e.

♻️ This comment has been updated with latest results.

…ields

- Add IsInitOnly, IsRequired, IsWritable to PropertyInfoExtensions
- Add IsRequired to MemberInfoExtensions and FieldInfoExtensions (new file)
- Add IsReadOnlyStruct and IsFileLocal to TypeMetaDataExtensions
- Add corresponding specs and update README

Closes #157

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@dennisdoomen
dennisdoomen force-pushed the dennisdoomen-init-only-required-readonly branch from eca8eae to 6554cbd Compare August 10, 2026 15:40
@dennisdoomen
dennisdoomen enabled auto-merge (rebase) August 10, 2026 15:42
Dennis Doomen added 2 commits August 10, 2026 17:51
Resolve conflicts with PR #174 (nullable reference type metadata) by
keeping both sets of additions in PropertyInfoExtensions.cs,
FieldInfoExtensions.cs, their specs, and README.md.
auto-merge was automatically disabled August 10, 2026 16:09

Rebase failed

@dennisdoomen
dennisdoomen merged commit f959a51 into main Aug 10, 2026
4 checks passed
@dennisdoomen
dennisdoomen deleted the dennisdoomen-init-only-required-readonly branch August 10, 2026 16:11
@dennisdoomen dennisdoomen added the enhancement New feature or request label Aug 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: Detect init-only, required and readonly members

1 participant