Proposal: Allow ‘this’ in field (and property) initializers #3247
Replies: 12 comments
-
There's no reason for this at all.
If you have a constructor and forget to initialize, the compiler will give you a warning that the property is declared non-nullable but remains uninitialized, specifically so you won't forget. |
Beta Was this translation helpful? Give feedback.
-
I locate my initialization code in an initialization method that is right next to the field declaration. This makes sense because (a) it allows the reader to associate the initialization with the field and (b) the field and the associated initializer are generated by a snippet in VS, so it is not really feasible to put the field assignment directly in the ctor. In this situation the compiler does not detect the fact that the field is being initialized by the initializer method that is called from the ctor. |
Beta Was this translation helpful? Give feedback.
-
The C# team chose to make initializers execute before the base constructor call. That makes referencing The only possible fix would be to move some of the initializers until after the base constructor call. This would enable referencing |
Beta Was this translation helpful? Give feedback.
-
Note that the VB.NET team made the opposite decision, they run all initializers after the base constructor call and allow for referencing |
Beta Was this translation helpful? Give feedback.
-
C# is adding support for this scenario. You'll be able to mark your helper initialization methods and the compiler will then understand what's going on in terms of initialization when you call it from the constructor. |
Beta Was this translation helpful? Give feedback.
-
@HaloFour to avoid a breaking change it would mean keeping the existing behavior but the additional initializers that refer to "this" would be run after the ctor instead of before. As to the two different behaviors, I don't think it would be confusing to most programmers. Most programmers don't think about this! The ones that run before the ctor currently are obviously not referring to 'this' so in most cases the programmer will not be interested in the state change occurring in the ctor. And the ones that do refer to 'this' will rather naturally expect the ctor to have already run. @CyrusNajmabadi WHEN ? ! Would be glad to have this. |
Beta Was this translation helpful? Give feedback.
-
Probably the next version. I believe @jcouv is working on this. |
Beta Was this translation helpful? Give feedback.
-
C# 9 will add support for the |
Beta Was this translation helpful? Give feedback.
-
Wouldn't it be cleaner to simply allow So instead of private Something? something;
public Something Something => something ??= new Something(this); We get public Something Something { get ; } = new Something(this); // Still an error, this doesn't exists yet.
public Something Something { get ; } ??= new Something(this); // Valid, this exists when attempting to get the property. Only downside is that the ??= symbol might be too easy to miss, so maybe a new public Something Something { get ; } ??= new Something(this); // Error, requires lazy keyword.
public lazy Something Something { get ; } ??= new Something(this); // Valid I personally believe this would be cleaner than putting attributes above methods, especially since you might look at a bunch of properties, but not realize there is a method with that attribute referring to that property that initializes that property. Especially since it's a coding convention to put properties together and put methods together. |
Beta Was this translation helpful? Give feedback.
-
This is yet another use case that falls out of the public Something Something => field ??= new Something(this); |
Beta Was this translation helpful? Give feedback.
-
@jnm2 oh i was actually thinking about how useful something like that would be. |
Beta Was this translation helpful? Give feedback.
-
I liked @jnm2's solution and maybe @Pentadome's one. One more thing to consider could be using the E.g. public record MyModel(IMyService Service)
{
public IObservable<int> MyEntities { get; } => Service.GetMyEntities().ToObservable();
} Instead of public record MyModel
{
public MyModel(IMyService Service)
{
MyEntities = Service.GetMyEntities().ToObservable();
}
public IObservable<int> MyEntities { get; }
} Or public class MyViewModel : ObservableObject
{
public IAsyncRelayCommand DownloadTextCommand { get; } => new AsyncRelayCommand(DownloadText);
private Task<string> DownloadText();
} instead of public class MyViewModel : ObservableObject
{
public MyViewModel()
{
DownloadTextCommand = new AsyncRelayCommand(DownloadText);
}
public IAsyncRelayCommand DownloadTextCommand { get; }
private Task<string> DownloadText();
} |
Beta Was this translation helpful? Give feedback.
-
We should be able to do this:
An inconvenience in c# 7, this has become a far greater problem in c# 8 because all non-nullable fields have to be initialized.
Without this, for a non-nullable type you have to either assign null! in the initializer (which introduces the possibility of a non-nullable type containing null, defeating the purpose of non-nullable types) or you have to assign a temporary value in the initializer and then replace it using an assignment in the ctor (which is ugly, not very efficient and also prone to errors because the initialization is separated from the declaration, you can easily forget to initialize).
Noting in advance I am not a compiler expert, so please tread lightly when you comment on the challenges of this idea :-)
Beta Was this translation helpful? Give feedback.
All reactions