Field keyword in properties: directly assign backing field in constructor #8704
Replies: 8 comments 25 replies
-
IIRC writing to the property from the constructor has always invoked the setter accessor method, with the one exception of readonly auto-properties where there is no setter accessor method. IMO, bypassing the setter in this case would be just as surprising as it could be expected to validate input received in the constructor. |
Beta Was this translation helpful? Give feedback.
-
I'm not sure what is being asked for here. There isn't an actual proposal that addresses the concern raised in the OP. Note: a constructor not being able to assign into an auto-prop directly is already a limitation in the language, even prior to 'field'. For example: class C
{
virtual int Prop { get; set; }
public C()
=> this.Prop = ...; // doesn't access the field.
}
|
Beta Was this translation helpful? Give feedback.
-
It seems like the ask is for ordinary constructors to be able to run code based on constructor parameters and initialize the property's backing field directly, just like primary constructors can. What if we could "teleport" the class SomeViewModel
{
public SomeViewModel(int value)
{
// [extra statements] here
init SomeProp = SomeCalculation(value);
}
public int SomeProp { get; set => { field = value; RecalculateAndUpdate(); } }
} This would maintain equivalence with what is possible with primary constructors today, while also allowing you the benefits of being able to add statements to the constructor which you cannot do with primary constructors today: class SomeViewModel(int value)
{
// But no place for [extra statements]!
public int SomeProp { get; set => { field = value; RecalculateAndUpdate(); } } = SomeCalculation(value);
} |
Beta Was this translation helpful? Give feedback.
-
To be honest, I find it really weird that semi-auto-properties allow for initializers at all, and that such an initializer bypasses the |
Beta Was this translation helpful? Give feedback.
-
I opened #9028 to try and articulate why I think this use case matters and how to address it. |
Beta Was this translation helpful? Give feedback.
-
I'd definitely use this feature in ViewModels for a project I'm using that has ReactiveUI and DynamicData. I just refactored one of my ViewModels to take advantage of field-backed properties to clean up having as many backing properties in scope. Old Codepublic class ViewModel
{
public ViewModel()
{
_someCollectionSourceList
.Connect()
.Bind(out _someCollection)
.Subscribe();
}
protected readonly SourceList<string> _someCollectionSourceList = new();
protected readonly ReadOnlyObservableCollection<string> _someCollection;
public ReadOnlyObservableCollection<string> SomeCollection => _someCollection;
} Current Codepublic class ViewModel
{
public ViewModel()
{
}
protected readonly SourceList<string> _someCollectionSourceList = new();
[field:MaybeNull]
public ReadOnlyObservableCollection<string> SomeCollection
{
get
{
if(field == null)
_someCollectionSourceList
.Connect()
.Bind(out _someCollection)
.Subscribe();
return field;
}
}
} If this proposal was implemented, I could get rid of field-backed properties entirely and switch to public class ViewModel
{
public ViewModel()
{
_someCollectionSourceList
.Connect()
.Bind(out fieldof(SomeCollection))
.Subscribe();
}
protected readonly SourceList<string> _someCollectionSourceList = new();
public ReadOnlyObservableCollection<string> SomeCollection { get; } PS: The collections are protected so I can subclass them and inject some fake data while working with the UI previewers. It would be great to be able to use fieldof in the constructor of a derived class like the following. I could see base classes needing to opt in to that behavior somehow since it'd bypass any logic in the setter. public class DesignTimeViewModel: ViewModel
{
public DesignTimeViewModel()
{
GetSomeDesignTimeData()
.Connect()
.Bind(out fieldof(base.SomeCollection))
.Subscribe();
}
} |
Beta Was this translation helpful? Give feedback.
-
I added an alternative Permit anywhere in the same type to the proposal for discussion purposes. This isn't the approach that I am proposing, but it seems like reasoning out the implications of this alternative would be useful. |
Beta Was this translation helpful? Give feedback.
-
The proposal |
Beta Was this translation helpful? Give feedback.
-
TLDR: It should be possible to assign the backing field of a property using the
field
keyword from the constructor.One use case of the new
field
keyword for properties isINotifyPropertyChanged
properties (e.g. in WinUI, WPF).The .NET Community Toolkit goes even further and allows source generated partial properties that use
field
in the generated code.One limitation with the
field
keyword is however, that it is no longer possible to initialize the backing field using a non-constant value without invoking the custom setter code. The setter code could i.a. contain a property changed event or logic to update the value in a database.This is especially undesirable in the constructor, when you for example want to initialize the property from a constructor-injected database object, but without it re-saving the value to the database again:
However, today it is already possible to assign parameters from a primary constructor to a property with a
field
keyword:This feels like a gap in the language that should be resolved IMO.
Beta Was this translation helpful? Give feedback.
All reactions