-
Notifications
You must be signed in to change notification settings - Fork 2
Fix ProtoInclude to respect SkipConstructor, add readonly member support, and make MemberStruct nullable #154
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
Conversation
Modified LightProtoGenerator to check SkipConstructor and use RuntimeHelpers.GetUninitializedObject when deserializing inherited types instead of calling the constructor. Co-authored-by: dameng324 <[email protected]>
|
@copilot run |
Co-authored-by: dameng324 <[email protected]>
This comment has been minimized.
This comment has been minimized.
|
@copilot add ReadOnly Property and field support for ProtoInclude,and Related tests |
…structor - Modified ToMessage generation for inheritance to use UnsafeAccessor for readonly members - Added helper method AssignReadonlyMemberInToMessage for inheritance scenarios - Added test InheritanceSkipConstructorWithReadonlyTests to verify readonly support - Disabled protobuf-net tests for the new test as it doesn't support this scenario Co-authored-by: dameng324 <[email protected]>
Done. Added readonly property and field support for ProtoInclude with SkipConstructor in a3636f0. Changes:
|
|
@copilot |
This comment has been minimized.
This comment has been minimized.
…nstructor=true - Modified ToMessage generation in inheritance scenarios to use FormatterServices for older frameworks - Added proper error handling for readonly members on pre-NET8 frameworks - Both ToMessage methods (base and derived) now support older frameworks with SkipConstructor Co-authored-by: dameng324 <[email protected]>
Done. Modified inheritance ToMessage methods to use FormatterServices.GetUninitializedObject for pre-NET8 frameworks when SkipConstructor=true in e8bd5cf. Changes:
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #154 +/- ##
=======================================
Coverage 98.72% 98.72%
=======================================
Files 101 101
Lines 2440 2440
Branches 250 250
=======================================
Hits 2409 2409
Misses 19 19
Partials 12 12 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
This comment has been minimized.
This comment has been minimized.
|
@copilot
When deserialize the this behavior is same as non-derived types. |
1 similar comment
|
@copilot
When deserialize the this behavior is same as non-derived types. |
- Made MemberStruct fields nullable (value types use ?, reference types already nullable) - Initialize members as null during parsing instead of using initializers - Check if members are not null before assigning in ToMessage methods - Updated WriteTo and CalculateSize to properly handle nullable members - Matches behavior of non-derived types which use HasValue flags Co-authored-by: dameng324 <[email protected]>
Done. Made MemberStruct members nullable and added null checks before assigning in dc9c971. Changes:
Done. Made MemberStruct members nullable and added null checks before assigning in dc9c971. Changes:
|
Refactored LightProtoWriter generation logic for better maintainability and code reuse. Enhanced handling of init-only and read-only members in message construction. Updated tests to cover new member scenarios and suppressed additional test warnings.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This pull request fixes ProtoInclude inheritance to properly respect the SkipConstructor setting when deserializing derived types. Previously, inherited types with ProtoInclude always invoked constructors during deserialization, regardless of the SkipConstructor setting. The PR also adds support for readonly properties and fields through UnsafeAccessor (NET8+) or FormatterServices (pre-NET8), and makes MemberStruct members nullable to track whether they were set during deserialization.
Changes:
- Modified code generation to use
RuntimeHelpers.GetUninitializedObjectorFormatterServices.GetUninitializedObjectwhen SkipConstructor=true - Added UnsafeAccessor-based assignment for readonly members (NET8+ only)
- Made MemberStruct fields nullable with proper null checking to match non-derived type behavior
- Added comprehensive test coverage for SkipConstructor with and without readonly members
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| LightProtoGenerator.cs | Modified ToMessage generation logic to respect SkipConstructor, added nullable MemberStruct members, implemented readonly member assignment via UnsafeAccessor, and added helper methods |
| InheritanceSkipConstructorTests.cs | New test validating constructor is skipped during deserialization when SkipConstructor=true |
| InheritanceSkipConstructorWithReadonlyTests.cs | New test for readonly properties and fields with SkipConstructor (NET8+ only) |
| InheritanceInterfaceTests.cs | Removed SkipConstructor=true to isolate test scenarios |
| InheritanceAbstractTests.cs | Removed SkipConstructor=true and added IntValue member for testing |
| NonGenericSerializerTests.cs | Fixed null-forgiving operator usage for nullable type tests |
| LightProto.Tests.csproj | Suppressed TUnit0046 warning |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Extract common field name lookup logic into GetReadonlyMemberFieldName helper - Improve code clarity with better comments and variable naming - Remove commented-out code - Use StringBuilder for string concatenation in loops - Rename valueAccess1 to unwrappedValue for better readability Co-authored-by: dameng324 <[email protected]>
This comment has been minimized.
This comment has been minimized.
Added .github/copilot-instructions.md with guidelines for using GitHub Copilot in the LightProto repository. Updated LightProto.slnx to include new and existing .github files. Cleaned up .codacy.yml by removing engine configuration and retaining only the test exclusion path.
|
Fix ProtoInclude inheritance to respect SkipConstructor setting
Summary
Fixed the issue where ProtoInclude inheritance types were invoking constructors even when
SkipConstructor=truewas set on the derived type. Additionally added support for readonly properties and fields in ProtoInclude scenarios with SkipConstructor. Now also supports older .NET frameworks (pre-NET8) by using FormatterServices.GetUninitializedObject. MemberStruct members are now nullable and only assigned when present in the proto stream, matching the behavior of non-derived types.Root Cause
When deserializing inherited types with ProtoInclude, the generated
ToMessage()method was creating instances usingnew ClassName()which always invokes the constructor, regardless of theSkipConstructorsetting. Additionally, readonly members couldn't be assigned after object creation without special handling. MemberStruct members were not nullable, causing all fields to be assigned even when not present in the proto stream.Changes Made
InheritanceSkipConstructorTests.csvalidates constructor is skipped during deserializationLightProtoGenerator.csnow checksSkipConstructorsetting in two places:SkipConstructor=true:RuntimeHelpers.GetUninitializedObject(typeof(ClassName))with UnsafeAccessor for readonly properties and fieldsFormatterServices.GetUninitializedObject(typeof(ClassName))and throws error if readonly members exist (since UnsafeAccessor is unavailable)AssignReadonlyMemberInToMessagehelper method that uses UnsafeAccessor pattern to assign readonly members in inheritance ToMessage methods (NET8+ only)InheritanceSkipConstructorWithReadonlyTeststo validate readonly properties and fields work correctly with ProtoInclude and SkipConstructorType?syntaxnullduring parsing instead of using initializersHasValueflagsGetReadonlyMemberFieldNamehelper methodSkipConstructor=false, continues to usenew ClassName()syntax with null-coalescing to initializersVerification
RuntimeHelpers.GetUninitializedObjecton NET8+FormatterServices.GetUninitializedObjecton pre-NET8InheritanceSkipConstructorWithReadonlyTestsuses UnsafeAccessor for readonly membersnew ClassName()Original prompt
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.