Apr 29, 2020 · 23 comments · 36 replies
-
The above would be great. Just needed it and never knew we only got partial classes and methods.
Beta Was this translation helpful? Give feedback.
You must be logged in to vote
All reactions-
Can you explain why they would be great? What use cases would they solve? How would the syntax work? What does a "partial" getter do?
Partial methods have some fairly strict rules. They exist for the purpose of generated/designer code to expose specific optional integration points. That's why partial methods must be private and must not return a value. It's entirely optional to provide an implementation, and if that implementation is not provided those partial method invocations are erased. None of that seems to make sense with properties.
Beta Was this translation helpful? Give feedback.
You must be logged in to vote
9 replies
-
@ewerspej The limitations with this approach have been discussed at length, both here and in #6420.
Beta Was this translation helpful? Give feedback.
-
Also, this pattern, where a property is generated from a field, incurs the risk that a developer may mistakenly write to the field
foo
instead of the propertyFoo
, thus bypassing the change notification code. If the field was generated from a partial property, it would be easy for the generator to create a name impossible to mistake.
That risk exists with all properties that have backing fields, thus this is not a valid argument against decorating fields with source generators.
Beta Was this translation helpful? Give feedback.
-
Since the property is written by the generator from the field, any other tooling around the property goes to the generated code, instead of the place where the field is defined by the developer. Of course tooling could be improved, but by instead allowing partial properties and decorating those, everything else in the ecosystem remains the same and just works. As that's what the developer defined and that's where going to definition or bindings, etc... will take you now.
Beta Was this translation helpful? Give feedback.
{{actor}} deleted this content .
-
IMO, the developer should always explicitly define the exposed surface of a type.
The code generator is simply taking over a part of the developer's job, it's merely automation for something the developer would normally do manually. Since the developer knows that a property is being generated, she's also explicitly defining the exposed surface by extension.
Requiring the developer to define implementation details and having the source generator emit that exposed surface is very backwards and is only the approach taken today specifically because features like partial properties don't exist.
Backing fields are always required for the scenario that the INotifyPropertyChanged
and INotifyPropertyChanging
interfaces are being implemented. Any developer using these source generators who also has previously implemented properties like this manually knows this.
There's nothing backwards about this, IMHO.
Beta Was this translation helpful? Give feedback.
-
The code generator is simply taking over a part of the developer's job, it's merely automation for something the developer would normally do manually.
The developer should express the public surface manually, and allow the source generator to fill in the necessary implementation details. So yes, the current pattern is backwards, only because a better option does not exist. With partial properties, there will be a better option, and I suspect source generators will largely move to using them and drop the current pattern.
Backing fields are always required for the scenario that the
INotifyPropertyChanged
andINotifyPropertyChanging
interfaces are being implemented.
Even if that was true, it's an implementation detail, one that the developer should not concern themselves with, nor even have direct access to.
Yes, everything is backwards about the current pattern with source generators and properties, for lack of a better option.
Beta Was this translation helpful? Give feedback.
-
The team is planning partial properties for a future version of C#, but decided there wasn't time for C# 9.
Beta Was this translation helpful? Give feedback.
You must be logged in to vote
1 reply
-
They need to get better at making time, perhaps a time machine.
Beta Was this translation helpful? Give feedback.
-
The use case I have is that I need to be able to add metadata to auto-generated properties.
Beta Was this translation helpful? Give feedback.
You must be logged in to vote
0 replies
-
@TonyValenti You might be able to use the TypeDescriptor stuff for that, although it's less convenient.
Another great use-case would be for implementing INotifyPropertyChanged using source generators.
Beta Was this translation helpful? Give feedback.
You must be logged in to vote
1 reply
-
That is certainly one obvious example, although I believe that the obvious uses go beyond the limitations of that one interface.
Beta Was this translation helpful? Give feedback.
-
The team is planning partial properties for a future version of C#
Apparently not after all. See notes at #3413
Beta Was this translation helpful? Give feedback.
You must be logged in to vote
1 reply
-
It is a must. Maybe in C# 12.
Beta Was this translation helpful? Give feedback.
-
The use case I have is that I need to be able to add metadata to auto-generated properties.
What kind of metadata do you mean? Attributes?
Beta Was this translation helpful? Give feedback.
You must be logged in to vote
0 replies
-
The notes there are honestly worded far more strongly than I remember our decision being.
Beta Was this translation helpful? Give feedback.
You must be logged in to vote
0 replies
-
Beta Was this translation helpful? Give feedback.
You must be logged in to vote
0 replies
{{actor}} deleted this content .
-
In my opinion, partial properties would be a very good fit with source code generators in a variety of cases where the code for a property is used repeatedly. The most obvious case are ViewModels, where you have a lot of properties that basically do the same: get and set the value and call the OnPropertyChanged
method.
Writing this inside a class deriving from each library's view model base class:public partial string MyProperty {get; set;}
Could allow generation of this code:
public partial string MyProperty {
get => _MyProperty;
set {
_MyProperty = value;
OnPropertyChanged(nameof(MyProperty));
}
}
Beta Was this translation helpful? Give feedback.
You must be logged in to vote
1 reply
-
This is precisely my use case.
Beta Was this translation helpful? Give feedback.
-
That is literally one of the first examples they give for source code generators - you supply an attribute-tagged backing field and it produces the property for you. That way, you don't need a partial property.
[AutoNotify("MyProperty")] private string _myProperty;
Beta Was this translation helpful? Give feedback.
You must be logged in to vote
3 replies
{{actor}} deleted this content .
-
It's less than ideal though: properties can have varying accessibility, or be virtual. With partial properties, it's easy and natural for the user to be able to specify that, and an SG to fill in the gaps. With the backing-field approach, you need to be able to specify all of that stuff in the attribute, which means introducing more domain-specific knowledge:
[AutoNotify("MyProperty", Getter = Accessibility.Protected, Setter = Accessibility.Private, IsVirtual = true)] private string _myProperty;
looks a lot worse than:
protected virtual partial string MyProperty { get; private set; }
Beta Was this translation helpful? Give feedback.
-
I don't disagree with partial properties, but IMO this feels like a better opportunity to wade into AOP scenarios for source generators. Otherwise these source generators are going to only grow in complexity as they have to absorb all of the different features that could otherwise be solved by user code, e.g. validation, normalization, etc.
Beta Was this translation helpful? Give feedback.
-
In addition to @canton7 's point, attributes on backing fields don't automatically lead to IDEs understanding that the typed property exists until the code is compiled, plus one could write an implemented setter or getter, and a source generator could then infer what it needs to write for the other accessor. There is no non-static-context opportunity to define anything in an attribute.
As for @HaloFour 's point, the availability of source generators does not mean that they "have to" be used for anything.
Beta Was this translation helpful? Give feedback.
{{actor}} deleted this content .
-
I believe the having the property on the human written code would allow the backing field to become a hidden implementation detail. It could be tagged to prevent it from appearing on intellisense thus making it very difficult to misuse the field instead of the property.
Moreover, I don't see much difficulty in implement it, as they would be following the rules already laid for partial methods on C#9 (compulsory implementation, etc.)
Beta Was this translation helpful? Give feedback.
You must be logged in to vote
0 replies
-
Allowing for edition of existing code as proposed in #3772 would reduce the need for partial properties, as their implementation could be modified without being marked partial.
Beta Was this translation helpful? Give feedback.
You must be logged in to vote
0 replies
-
Another reason why partial properties will be superior for INPC than the approach of letting the user specify a backing field, and then having an SG which generates the property: it's hard to find references to a property which an SG has generated from a backing field.
You need to find the SG-generated partial class (which can be quite a few clicks), then find the generated property within that, and then you can find all references. Frankly, it's easier to use Find in Files.
If we had partial properties, you'd be able to just find all references there and then, rather than having to do digging.
Beta Was this translation helpful? Give feedback.
You must be logged in to vote
0 replies
-
I'm interested in helping to make partial properties happen, but I honestly don't know what the design would be. One issue I see is how to distinguish the "implementation" part of the property from the "declaration" part:
// This partial property is implemented using a simple auto-property. // but which part is the implementation? public partial string Prop { get; set; } public partial string Prop { get; set; }
I guess you could introduce a modifier just for partial properties to convey that one of the parts is an "implementation" part.
public partial string Prop { get; set; } public auto partial string Prop { get; set; }
You could also make it so at least initially, partial properties can't be implemented with auto properties. After all, it seems like the stuff people really want to accomplish with this feature doesn't involve auto-implementing the property.
Beta Was this translation helpful? Give feedback.
You must be logged in to vote
All reactions4 replies
-
You could also make it so at least initially, partial properties can't be implemented with auto properties.
That seems most sensible. If the main use case is source generators, having to write it out in full shouldn't be a problem, especially is the field keyword is introduced so the field wouldn't be visible.
Beta Was this translation helpful? Give feedback.
-
Agreed, I personally don't see any use for a partial property which is fully auto implemented. To me, the point of a partial property is so that one part of it can have some logic on the getter/setter.
Beta Was this translation helpful? Give feedback.
-
I believe that, while there is no real reason for partial properties to not contain any actual logic in their accessors, it shouldn't be prohibited to declare a partial auto-property, without any extra syntax. The example
public partial string Prop { get; set; } public partial string Prop { get; set; }
could be valid in that case, since both declarations of the partial property do not explicitly implement the accessors. This results in having a total merged declaration of an auto-property. The generator of choice could potentially avoid checking whether the property needs auto-implementation and is already defined, where it would safely assume it's right to declare it as if it's an auto-implemented property.
Additionally, auto-implemented partial properties could include multiple declarations with parts of their accessors being split across multiple. For example,
public partial string Prop { get; } public partial string Prop { set; } public partial string Prop { get; set; }
Since all declarations only include a accessor definitions, the result is a full auto-implemented property, like above. This also has no reason to not be valid, as we're talking about source generators being involved in the reasoning behind this feature's existence.
As I view it, the main concern around implementing features predominantly regrading source generators is lenience. Invalidating scenarios that can be safely and definitely interpreted correctly stands out of place.
Beta Was this translation helpful? Give feedback.
-
Later this summer I anticipate we will be in the phase of building up more proposals for C# 12, and I'll plan to write a partial properties proposal at that time for LDM to discuss.
Beta Was this translation helpful? Give feedback.
-
I wonder whether partial events would be considered as well. It is quite useful when implementing async events and weak events.
Beta Was this translation helpful? Give feedback.
You must be logged in to vote
5 replies
{{actor}} deleted this content .
-
I long ago convinced myself that weak events are a fool's errand (at least without compiler/language support!), but that's an entirely different discussion!
Beta Was this translation helpful? Give feedback.
{{actor}} deleted this content .
-
Yes I have seen many people say so, but I still think it's useful in some cases. Given IDisposable
, .NET's finalizer is the same, but we still have it, and the framework still implements it with extreme carefulness.
For example, even if you don't want to rely on it, it's much better to use the weakness to print some warnings when you debug and test than doing nothing when it silently leaks.
Beta Was this translation helpful? Give feedback.
-
As in, it's downright impossible. See #4039
Beta Was this translation helpful? Give feedback.
{{actor}} deleted this content .
-
@canton7 I agree that it is impossible to provide a perfect, generic weak event, but, as I said, it is still useful in some cases. The point is, if you assign arbitrary delegates, especially those constructed from closures, the weak event pattern can easily fail. But that doesn't render it useless. There are plenty of language features that will break if you don't know how to use it correctly. Note that I am not suggesting to add weak event itself to the language. I am asking to add a feature, which, in addition to other use cases, would help users who need it to add the weak event pattern by themselves.
If you are curious I can share more but I don't think this is a good place to discuss this issue.
Beta Was this translation helpful? Give feedback.
-
See this discussion about partial events: #8064
Beta Was this translation helpful? Give feedback.
-
For XAML frameworks like WPF or Avalonia it would be insanely useful to generate dependency properties. See discussion in Avalonia repo AvaloniaUI/Avalonia#6315 (comment)
[RegisterDirectProperty]
public partial int BorderThickness { get; set; }
Would auto generate:
public static DirectProperty BorderThicknessProperty = ...;
private int _borderThickness;
public partial int BorderThickness
{
get => _borderThickness;
set => this.SetAndRaise(BorderThicknessProperty, ref _borderThickness, value)
}
Beta Was this translation helpful? Give feedback.
You must be logged in to vote
0 replies
-
Definitely would love having partial properties too. We use attributes over fields in the MVVM Toolkit to generate observable properties, but it's really not a great experience at all. To name a few issues it has that would be resolved if we had partial properties:
Honestly having partial properties with the restriction that the implementation can't be an auto-property seems perfectly reasonable to me, and it would solve the issue of determining which declaration is the implementation and which one is the partial one. But really, having partial properties is really needed in scenarios where source generators are involved, such as this one. Really hope the LDM will consider this again maybe for C# 12, at this point 🙂
Beta Was this translation helpful? Give feedback.
You must be logged in to vote
8 replies
-
We use attributes over fields in the MVVM Toolkit to generate observable properties
Is there a reason the upcoming field
keyword feature wouldn't solve these problems?
public string ObservableProperty { get; set => SetAndNotify(ref field, value); }
A partial void method with no provided implementation will be the equivalent of
{ }
Not quite: a partial void
with no implementation is the equivalent of no method at all.
Beta Was this translation helpful? Give feedback.
{{actor}} deleted this content .
-
"Is there a reason the upcoming field keyword feature wouldn't solve these problems?"
The field
keyword will make explicit properties much less verbose to implement, but it won't help when you had scenarios with dependent properties or commands as well. The point of generated properties is that they make it simpler to handle those cases, without having to add all the boilerplate code to deal with dependent updates. Consider this scenario:
[ObservableProperty] [AlsoNotifyChangeFor(nameof(FullName))] [AlsoNotifyChangeFor(nameof(IsValid))] [AlsoNotifyCanExecuteFor(nameof(SubmitCommand))] private string name;
This will generate:
public string Name { get => name; set { if (SetProperty(ref name, value)) { OnPropertyChanged("FullName"); OnPropertyChanged("IsValid"); SubmitCommand.NotifyCanExecuteChange(); } } }
You can see how having field
doesn't help at all here. Whereas with a partial property:
[ObservableProperty] [AlsoNotifyChangeFor(nameof(FullName))] [AlsoNotifyChangeFor(nameof(IsValid))] [AlsoNotifyCanExecuteFor(nameof(SubmitCommand))] public partial string Name { get; set; }
Perfection 😄
Beta Was this translation helpful? Give feedback.
-
With the current use of having to use fields for this it means that properties for serialization and database usage that go on properties can't work or be known to forwarded easily, see our issue tracking that here: CommunityToolkit/dotnet#208
Beta Was this translation helpful? Give feedback.
-
Blocked based on unauthorized use of Llamas in an MS context.
Beta Was this translation helpful? Give feedback.
{{actor}} deleted this content .
-
Another use case is cross-platform code. Currently MAUI recommends implementing it with partial
classes: https://docs.microsoft.com/en-us/dotnet/maui/platform-integration/invoke-platform-code#define-the-cross-platform-api
But what if I want a cross-platform property? Here's an example that changes app theme on Android:
// Shared code public partial class NightModeService { public partial NightModeStyle DefaultNightMode { get; set; } } public enum NightModeStyle { Unspecified = -100, FollowSystem = -1, No = 1, Yes = 2, AutoBattery = 3 } // Platform-specific code public partial class NightModeService { public partial NightModeStyle DefaultNightMode { get => (NightModeStyle)AppCompatDelegate.DefaultNightMode; set => AppCompatDelegate.DefaultNightMode = (int)value; } }
Beta Was this translation helpful? Give feedback.
You must be logged in to vote
2 replies
-
What do partial properties offer in this scenario you proposed?
Beta Was this translation helpful? Give feedback.
{{actor}} deleted this content .
-
@alfasgd Updated the code snippet to better demonstrate use of partial property.
partial
class without the implementation is defined in the shared code, and each platform defines the implementation part (both parts are in the same project thanks to multitargeting and conditional compilation (<SingleProject>
))
This ensures that implementation is present and has the same signature on all platforms.
Beta Was this translation helpful? Give feedback.
-
I've come across another slightly subtle issue, which partial properties would solve nicely.
The motivating example is an INPC source generator, where the user writes a backing field and the SG generates the corresponding property. A common feature of such tools is to be able to automatically generate a PropertyChanged event for one property when a property that it depends on changes, e.g.:
partial class C { [Notify] private string _foo; // Generates the Foo property public string Bar => Foo.ToUpperCase(); }
Here, we want to raise a PropertyChanged notification for Bar
when Foo
changes. This is fine, and a SG can inspect the contents of the Bar
getter to see that it references Foo
.
The problem is that when the SG runs, Foo
doesn't exist yet. After all, it's the SG's job to generate Foo
. Therefore, the reference to Foo
is just an IdentifierName
with an Invalid IOperation
. To find out that the identifier Foo
will end up binding to a property which the SG is about to generate, the SG essentially has to start re-implementing bits of the compiler's binder.
This gets even more complex if you start trying to support things like:
partial class Parent { [Notify] Child _child; public string ChildName => Child.Name; }
Partial properties would solve this nicely, because the syntax tree that the SG sees would have been properly bound. Foo
would already be bound to the partial property of the same name, and the SG wouldn't have to replicate this logic.
Beta Was this translation helpful? Give feedback.
You must be logged in to vote
0 replies
{{actor}} deleted this content .
-
I too would like to have partial properties. I'd like to generate json metadata for STJ and Newtonsoft at the same time using partial classes and partial properties. Like so:
public partial class Entity { public partial int Id { get; set; } }
Generated code:
public partial class Entity { [System.Text.Json.Serialization.JsonPropertyName("id")] [Newtonsoft.Json.JsonProperty("id")] public partial int Id { get; set; } }
Beta Was this translation helpful? Give feedback.
You must be logged in to vote
0 replies
This comment was marked as off-topic.
This comment was marked as off-topic.
-
Beta Was this translation helpful? Give feedback.
You must be logged in to vote
0 replies
-
Beta Was this translation helpful? Give feedback.
You must be logged in to vote
0 replies
Converted from issue
This discussion was converted from issue #3412 on November 25, 2020 13:28.
Heading
Bold
Italic
Quote
Code
Link
Numbered list
Unordered list
Task list
Attach files
Mention
Reference
Menu reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emojiRetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4