Flattened Property Composition: A Type-Safe and Declarative Alternative to Inheritance in C# #8770
Unanswered
humayunkhan
asked this question in
Language Ideas
Replies: 1 comment 14 replies
-
You could use a struct to define the data members and use a source generator to create the delegating properties. I don't see this as a language feature as it wouldn't work well at all across assembly boundaries as the internal state of a class may not be known at the time of compilation or could change between compilation and runtime. |
Beta Was this translation helpful? Give feedback.
14 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Summary
C# currently lacks a native, concise, and type-safe way to include properties of one class in another without using inheritance or manually duplicating properties. This proposal suggests introducing a new feature that allows flattened property composition using the include keyword, enabling developers to declaratively reuse properties from another class while adding their own. This feature simplifies code, reduces redundancy, and improves maintainability.
Motivation
Currently, to reuse properties of one class (e.g., ClassA) in another class (e.g., ClassB), developers must:
None of these solutions provides an ideal balance of simplicity, type safety, and maintainability. A native feature for flattened property composition would address these shortcomings.
Proposed Syntax
1. Basic Syntax
Equivalent generated code:
2. Handling Read-Only Properties
The include keyword respects readonly and private set properties:
Equivalent generated code:
3. Delegation for Properties with Logic
Properties with custom logic or private dependencies are automatically delegated:
Equivalent generated code:
4. Handling Properties with Side Effects
Properties with interdependencies are also delegated to preserve side effects:
Equivalent generated code:
5. Conflict Resolution
If two included classes define properties with the same name, the compiler throws an error unless resolved explicitly:
Potential Solution: Use aliasing:
6. Customization with "with" Clause
Developers can customize inclusion behavior with a with clause:
Equivalent generated code:
Features and Benefits
Comparison to Existing Features
Use Cases
Corner Cases and Challenges
1. Circular Dependencies
Problem:
If two classes include each other directly or indirectly, infinite recursion could occur during compilation.
Example (Circular Dependency):
Solution (Compiler Check):
The compiler should detect such cases and throw a compilation error like:
2. Versioning and Compatibility
Problem:
Changes in the included class could break dependent classes if properties are renamed, removed, or modified.
Example (Breaking Change):
If ClassA changes like this:
The compiler should raise an error:
Error: Property 'Property2' is not defined in 'ClassA' but is expected by 'ClassB'.
Solution (Selective Inclusion):
Generated Code:
3. Reflection and Metadata
Overview:
The include feature should work seamlessly with C#'s reflection system to support tools like serializers, validation frameworks, and ORMs. This includes metadata propagation, custom attributes, and conflict resolution.
Reflection Scenarios and Solutions:
Property Discovery in Reflection
Example (Expected Reflection Output):
Reflection Code:
Expected Output:
Solution:
Properties generated through include should be fully discoverable using
Type.GetProperties()
.Metadata Propagation
Example (Data Annotations for Validation):
Validation Code:
Solution:
The compiler should automatically copy metadata attributes from the source class properties (ClassA) to the generated properties in the target class (ClassB).
Custom Attribute Customization
Example (Custom Attribute Override):
Reflection Code:
Solution:
The compiler should support metadata overrides using the
with
clause for fine-grained control.Origin Metadata Tracking
Example (Metadata Annotations for Property Origins):
The compiler could automatically generate a special attribute like
[GeneratedProperty]
for included properties:Reflection Code:
Expected Output:
Name was included from ClassA
Metadata Conflicts
Example (Conflicting Attributes):
Reflection Code:
Solution:
with
clause, custom attributes override inherited attributes.4. Immutable Record Types
Problem:
Including mutable properties in immutable records would break immutability principles.
Example (Invalid Use):
Solution (Enforce Immutability):
The compiler should enforce immutability rules for included properties in records:
Generated Code:
5. Overuse and Abuse
Problem:
Developers might overuse the feature, creating bloated classes with too many properties.
Example (Overuse):
Solution (Best Practices & Static Analysis):
A similar proposal
#5897
Conclusion
The
include
keyword enables simplified property composition while maintaining type safety, reducing boilerplate, and offering customization. It complements existing C# features like inheritance, composition, and source generators while offering a more concise and native experience.Beta Was this translation helpful? Give feedback.
All reactions