Why I won’t need constructors anymore in C# 11
HTML-код
- Опубликовано: 6 сен 2024
- Check out my new "Integration testing in ASP .NET Core" course and use code INTESTING1 for 20% off (first 300): dometrain.com/...
Become a Patreon and get source code access: / nickchapsas
Hello everybody I'm Nick and in this video I will introduce you to the brand new "required" keyword that is being added in C# 11. It is a great language feature that solves one of my biggest problems with object initialization, and it eliminated the need for constructors for that usecase.
Link to the required keyword feature issue: github.com/dot...
Don't forget to comment, like and subscribe :)
Social Media:
Follow me on GitHub: bit.ly/ChapsasG...
Follow me on Twitter: bit.ly/ChapsasT...
Connect on LinkedIn: bit.ly/ChapsasL...
Keep coding merch: keepcoding.shop
#csharp #dotnet
For those wondering, yes the required keyword IS coming in C# 11. It was demoed at Build and NDC Copenhagen and I confirmed it with Mads Torgersen himself
would you be able to use it to write api's? API should be simple.
This is great news! Will it play nicely with deserialization, I wonder?
YES! FINALLY! 😄
No more boilerplate constructors duplicating every name and type of every property. Sheesh! We needed this 😅
@@DavidBondOnline that would likely be up the deserializer - it emits an attribute, which the compiler enforces at compile-time, but things like serializers, validators, mappers and DI containers will likely need to use reflection and respect this new attribute. So not a simple, ideal solution in that way - but it's too late for that, I guess. Established languages don't really make breaking changes, and the VM and run-times already support multiple languages - as with most popular software, complexity can only really go up from here. What makes this worth while, is the it lets you remove complexity from your code.
Look like it's not coming in C# 11. At least it's not mentioned in the release notes and the tracking issue is still open.
I was waiting a long time for this feature. I was really upset that it was removed from C# 10 release. As I said in the comments under one of the videos, required keyword is one of the most awaited thing for me in C# 11. I use nullable enabled a lot in my projects so required keyword will be the last thing I am missing to make my code safer and cleaner
I agree, I've been using constructors this entire time to ensure they are properly not null when using nullable it has lead to a way messier codebase than I would have liked
Was going to comment something very similar. Very nice that it's finally coming!
"Attribute constructor" means you could write something like [Required(FullName="Nick")] - because as you saw it's implemented with an Attribute. I haven't tested it though, and I'm not quite sure how that would make sense... unless it acts as a default value? (Or the error message needs some love.)
@@BadgersEscape I do that, makes my code look very enterprise/shitty
This feature should have been added when the Explicit Nullablity was added, I would have spent less time having to argue why setting a non-nullable string property value to null using null-forgiveness or empty string is not a good idea on models that have many of these properties that it would create an unwieldly large ctor. The more I see of 11 the more I look forward to its arrival.
Yeah I had to basically "lie" in my code and add all those "= default!" or "= null!" calls that are error prone. Finally I can remove them
Can you please elaborate on this, as I am not sure I understand. Let's say you have 10 "required" properties and you create a 10 parameter constructor for that. If you initialized the object the old way, you would have to pass 10 arguments in there. But if you use the required keyword, you still have to provide those 10 values, no? So how does this or Explicit Nullability make it less unwieldy?
Oh wow, finally, this is the most necessary feature i have been waiting for in my use case. This makes Initialization so much cleaner and improves on the nullable scheme C# has been moving towards. This removes so much unnecessary boilerplate code in my codebase that is only useful for making the compiler shut up about warnings, without any additional benefit.
You can finally say goodbye to those "= default!" calls. it also makes working with deserializer code so much easier
@@IIARROWS yes, but i have a personal policy on my code that i keep nullable on to write more safe code. I think nullable is a great addition and instead of circumventing warnings, we should introduce semantics that do not raise such warnings. This is why i like this new feature
@@IIARROWS well in fact it can be null. If you mess up and forget to provide the property. That's why I think = default! (except for injected values) or turning off NRT is a bad idea. Just create a constructor for required properties. With named parameters it almost looks like property initialization. That being said the required keyword is better and I will replace my constructors with it.
The discussion in the issue is very interesting. Personally I prefer "public string X { get; required init; }".
Likewise, I think this would add huge amounts of clarity to code.
I really like that they're adding more tools for api/tool code to demand correct usage through compiler errors rather than runtime errors, that's the most powerful thing a compiled language can do to help us
I just hope this works well with JSON serialization. That requires a parameterless constructor for deserialization anyways most of the time, so the required keyboard spares me a lot of checking code. I appreciate it immensely. And I also also highly appreciate the work you're doing with Videos and courses.
Constructors also work though. Been using records with json serialization which are very concise for this.
Any updates on this? I remember using deserialization skipped a lot of the initialization rules we had in the past, such as defaulting a property to an empty collection, both in the constructor or as a default property assignment. C# basically just created an object from what it was given and ran nothing else, so it always made sense for us to just have a validation service that would run. Or in this case, "correct" the data. Treating it like a DTO and then mapping to a full fledged object probably would have been the better choice, but live and learn when maintaining feature parity across multiple code bases simultaneously lol.
Attribute constructors means something like [Required(ErorrMessage="Error")] as an example
Oh I see! Thanks
Yes. I was thinking the same.
I thought the same.
This helps patch the huge hole created with non-nullable types on properties. Now you won't be able to forget to initialize those important properties. Constructors were sometimes an option but often felt too clunky to use. I'm so glad this feature is finally coming to c#.
I felt it when you showed the constructor where each line had a value to pass in required fields. I’ve been in that scenario far too many times. I was also in a bit of a pickle because the settings for our quality gate, SonarCloud, restricted the number or arguments for methods including constructors. So in the end I ended up resorting to “smuggling” arguments in a class solely built for passing all the arguments I needed. I do like the idea of transforming object initializers into de facto customizable constructors with the ability to declare required properties. I’ve been out of the loop for a while due to health issues so I’ve been enjoying catching up watching Nick. Thanks Nick!
This is fantastic. Constructors are such an old legacy way of initializing things and being able to not have to use one is amazing 🤩
Really glad to see this finally making it into the language, I've wanted this feature for a long time.
Seems almost like a constructor with braces instead of parentheses. Defining by marking the properties themselves as required is nicer than defining the same concept in a constructor. But it is basically the same thing.
That would be WONDERFUL!! I'll use it a lot... well it depends on what exactly mean "required" for a string.
This is great in theory, but only for simple constructors. Any time you have to initialize a collection property with an empty List, you’ll be right back to doing it the old way.
You can just initialize the property with an empty list. No need to do that in a ctor.
Oooo this is nice, I can stop using named parameters to essentially get the nice explicitness of initiaze lists with required variables
I'll be using it for sure. I was actually waiting for such a feature.
I love it. I have hated constructors for dto unless you go the full record route. And doing nullable makes it more difficult because you have to assign fake values everywhere. Now you can just require and not deal with string.empty everywhere.
Thank you as always
I have expected for this for long time.
I got tired of using ctor just to enforce required members initialization.
I Think I would use that a lot!
I kind of take the opposite view: Where initializers exist, they're evidence of a deficiency in the provided constructor(s) on the class. If you have to assign 10 properties to the object to initialize it correctly, the problem isn't that you have a really big constructor; it's that you have a God Object that needs massive amounts of initialization to work correctly.
Dude gets people hyped for a c# release like none other
The benefit of having constructors is it makes your classes neater IMO. The logic for setting a properties of a class should be within the class itself otherwise you end up having instanciations of your object all over the project. It also makes it easier to read what's implementing that object when using the "2 references" (visual studio enterprise)
The required keyword on it's own is not meant to replace any meaningful "logic" that would usually be found in a constructor. Instead it is replacing the unnecessary legwork of having to create huge unwieldy constructors which do nothing but take a bunch of mandatory parameters and assign them to properties/fields.
If you want to implement custom logic during initialization you can still use constructors as before for those properties/fields that need it and use the required keyword for all other mandatory ones. Same as you would use auto properties to simplify get/set access to a single line and only implement custom get/set logic as needed.
Also another neat C#11 feature which Nick has not mentioned goes very well with this:
You get field access in auto properties: Each accessor in an auto property will be able to implement themselves and can *refer* *to* *the* *automatically* *allocated* *backing* *field* with the fittingly named keyword *"field".* Example:
public required string FirstName { get; init => field = value.Trim() }
I wonder if this can be made to eliminate the boilerplate around defining and assigning dependencies in dependency injection
Maybe this? public required IFoo Foo { init; }
I like this, I always preferred to use constructor parameters but this approach makes it even better
With the 'required' keyword on the horizon, it feels like C# is finally turning up the volume on its safety feature. Forget constructors, it's all about concise and clean code now. It's like spring cleaning, but for our codebase!
Nick - thank you for such a well explained video on the upcoming feature.
I’m curious to see if classes with the [RequiredMember] attribute will impact Activator.CreateInstance()… mainly from the perspective of a library/framework maintainer…
I haven't read through the proposal or related media, but based on what I saw here it looks like it's something that only happens at compile time for statically known things, which Activator and co. already don't care about. I imagine this changes nothing since the default constructor should still exist, but I can see a world where they throw an exception I guess.
Note that properties are not the same as constructors, and the compiled code is much bigger, and thus inefficient compared to the constructors, because each property is set externally outside the class. Funny enough, we even bloat out the source code with by using Property = value and setting each property on a new line and such.
I think records is one of the features that really helped with making classes short and clean. Plus, when implementing a new feature you can add a parameter to your constructor, or another parameter to the record, and you can safely go through all the places where the class has been instantiated. With properties it's a little harder, since you can't really see where it has been created.
We really don't need any more ways to create a class neither instantiate the properties, seriously, we could write a top 10 ways to create an object in c#.
Yeah init was not enough. I was thinking about this yesterday and this video shows up. Kudos
Hi Nick. I just found your channel a couple days ago and I'm loving it! Keep up the good work!
Great video as always! I'm wondering if DI containers will support the required keyword. As far as I know, all of them rely on constructors for automatically determining which dependencies should be injected.
I don't think they will because I don't think it will solve the same problem. The main reason why required makes sense for POCOs (mostly) is that you actually initialize them yourself. For classes with injected dependencies, you never initialize them explicitly (except for unit testing when you pass the mocks)
lets wait 5 more versions of c# to have *inject* keyword 😀
This is great and I look forward to the required keyword, but at the same time, it shouldn't be required if the language was properly designed because we already have nullable and non-nullable data types, so it should already know that the property is required if it is not nullable, but I guess this is because of backwards compatibility.
Hey Nick, I would love to see an ASP Net Core class that ignores MVC and focuses purely on the API side using best practices such as mediator and any other libraries you reccomend. If one already exists usisng C# 10 it would be great to hear your reccomendation. All of the tutorials I find focus on MVC and not the API / server side of things. This is interesting for me as I mostly use Blazor WASM as a front end and having a rock solid server side deployment would help make my application enterprise ready.
This is awesome for writing API code and models and now would make the intent much better at compile time!
I like your videos.
And I like that you use allman braces. They're nicely readable for people with bad eyesight like me.
I saw that feature on dart and I’m glad it is coming to C# as well, great video, btw
Thank you! I would definitely use this. I have needed it for at long time. Also, if you need a xaml control that needed some startup properties, you can't use a constructor for that. As far as I know, there is not "logic" way of making it obvious for the user of your control, which fields are neccessary and which are not. I hope they will make this work with the xaml compiler, so it gets angry if the required fields are not set inside the control element, or at least an option to make it so.
My only issue is if some property is partially required. For example if another property is set like if MiddleName is set then FirstName is required. This should probably be solved by an abstract factory but constructors would also be a solution aka having Person(string first) { } Person(string first, string middle) { } Person(string first, string middle, string last) { }. However it would be good to put required on the first name.
While I like the idea of the feature, it takes away the ability to explicitly know how to create a class without dealing with errors. Having the values in the constructor at least tells you right away what is required to make the class. This feature you won't know, until you see errors.
So it just needs IDE support for suggestions, not a big deal to implement.
I'm sure they'll have that as well; however, how does that help when looking at documentation of a library? Now you not only have to look at constructors but the properties as well just to figure out how to instantiate it. I just fail to see how this speeds up development.
Reminds me how in records you don't see the argument names like in a property initializer
Agree, and what about polymorpishm, multiple constructors with different required parameters. This is ugly way. I can not imagine big app written with this way. Huh
@@jakubhantak1960 actually having multiple constructors that initialize different sets of properties is a code smell and this pretty much eliminates that code smell, so it's a win.
Once this was explained, I realized how useful it is. Cool!
15 seconds into the video and im already sold
that feature comes from dart, dart is the language of flutter, in dart you may declare a variable as required on the constructor then you must provide a initial value or the compiler throw a error
One my next new favorite C# features !!
Nick doesn't need constructors because he's simply so powerful he can instantiate objects by sheer force of will
what if i need to run a class method to initialize a property? i would normally run it in the constructor and assign its return value to the property but like this, without a constructor, i'd have to delegate that to an external method in order to call it during initialization. maybe this will come in handy for a few scenario but constructors will still be needed for complex inits
Very nice feature, thanks!
It will be one of the best features, especially with the recent null state analysis.
"= null!" no more
So much syntax sugar were added lately that I'm sure C# 69 would be the sweetest thing ever.
True!
Same thing with Python
Great news! That's one of the reasons I was so upset about using nullability features in C#. They forced me to use constructors to init properties. And I don't make use of constructors for most of my programming thigns.
This one seems really handy!
Seems like a huge design mistake by C# language designers that a init-only property of a non-nullable type does not need to be initialized during construction.
Trying to work around that mistake by adding yet _another_ keyword is really disgusting.
Why not fix the actual design mistake directly?
The semantics of init should not be that it is identical to a single-use setter (that could be called whenever you like .. or not at all).
Instead init should mean that initializing the property is part of the initialization of an object during its construction.
Case in point, with the design presented above, if I had a Widget class with 10 required string? properties, would I need to create an empty Widget like this:
new Widget () {
PropA = default,
PropB = default,
PropC = default,
// or nulls...
PropD = null,
PropE = null,
// and so on ...
}
?
Or is there yet another inconsistency in the design and there is some special handling for this?
That's a nice feature. The more boilerplate unnecessary code they can remove, the better c#/.Net coding experience gets.
I'd love to get rid of constructors just for dependency injection as well. Just add a "injected" keyword instead
How would you mock it? If you set it using object initialization it uses that, otherwise it injects? That'd be cool
Cool, something that I could never do before is now actually possible :). I wrote my own DI Container long time ago that uses MEF-like attributes and field-injection and I got massive problems with nullable-reference types. BTW, I love attributes because they tell me exactly how a class plays a role in the infrastructure in comparison to other DI DI containers where I have no clue whether the class should be manually instantiated or retrieved from DI container, I imidiatelly see what dependencies a class has, I don't need to use constructor and extra code to set the fields, and I don't need to register each class. For instance:
[Export]
public class C
{
[Import]
private D dependency;
}
I got warnings that property is not nullable but is also not initialized directly in code. I don't want it to be nullable because it is not optional and DI container will throw an error while bootstrapping the application if dependency is missing. Using "required" keyword could solve this big problem.
[Export]
public class C
{
[Import]
private required D dependency { get; init; }
}
I would have to use private properties instead, but it's fine and not much more code to write. But I need to experiment with the feature if it would actually work.
One of my main problems with records is actually that they don't have the pretty class init syntax. I think It is way more readable than using constructor when initting records (even though you can use named parameters). Very excited for this feature to land!
It's more verbose, but you can declare records and just not provide the parameter list. You'd be writing the same { get; init; } properties manually instead, but you get the initializer syntax back. For more complicated records this is what I currently do because the benefit of compiler generated Equals/HashCode is sometimes worth it, just missing the required marker still : (
hello Nick awesome content, I just bought your class about testing (used the code and still worked, yaay!), looking forward to watch it, what I would like to see more is some high performance optimizations, usage of spans, seems like C#11 is moving in that direction with utf support and patter matching, do you think Span will be for mainstream use and proliferate thru most modern c# codebases? Can you consider making course going in depth on this topic - performance, memory allocation and usage of span and memory?
There is actually a course about writing performant c# code coming hopefully this year. It’s really something I wanna make more content about
Convenient feature. if you have a ctor with 10 parameters maybe you could use a builder though
Builders are hard when you need to do programmatic stuff with that type, for example writing a serializer. I like it being an option but not the only way unless there is a very specific reason, for example guided initialization
This looks very nice, but i have a big problem with this feature. You cannot do any validation based on the member. A sample would be: You have the properties Start and End and want to validate that Start is smaller than end. How can you handle it with this feature? Constructor is called before any value is set and if you do the logic in the properties the order matters.
PS: Sorry for my bad english
You can add it in the setter which is really where it should be. Ctor only ensures the creation but not any subsequent value setting
Interesting choice of arbitrary number Nick
Love this feature, can't wait to use it
This great especially when doing refactoring. However multiple overloads was used to have some different options and flow, but given from the example using model I can see many reasons why.
Nick: Why I won't need constructors anymore
System.Text.Json: Hello
I've always just used the [Required] class annotation for my models
Well presented Νίκο! Thanks for the content!
Finally setting something = string.Empty to stop the compiler complaining is a thing if the past, long overdue feature!
I'd say: really neat for data classes but I wouldn't use this for anything that requires DI.
Say you need to register to an event on your dependency then this would now need to happen in the property setter. And I'd rather have all my initialization logic for a class in one neat place.
Also if you ever needed two of your dependencies for some initialization call you'd suddenly have an invisible required order of how your properties need to be set because otherwise the code breaks. And the bad part about it is of course that that requirement can happen down the line and then your only sensible approach to that would of course be to go back to having a constructor. But at that point that would be a breaking change (granted the Di-container really shouldn't care about that breaking change but all your unit tests will mind very much so it's still quite a hassle)
So tl;dr; will use that for POCOs but not for anything with logic.
Even though this wouldn’t be used for DI, it still gave me a feeling that DI could be trimmed down substantially with a similar approach. We’re almost always doing the same boilerplating in DI (except for e.g. the Options pattern), so reducing it all down to the field with a keyword such as ”inject” or something would make the code a lot more beautiful and completely remove the need for constructors in most cases!
Almost all DI already have this autowire properties functionality. But ctors are better. From point of view autofac is number one especially with optional injections, factory injections etc
@@ztBlackGad True but I don't want to use properties for DI. Just feels wrong to me. Private readonly variables only...
@@briankarcher8338 then how to mock dependencies? :)
@@ztBlackGad Constructor. These variables should be kept encapsulated.
@@ztBlackGad Mind you, I wouldn't mind some sort of attribute or something to mark a private field as an injected field as mentioned by others in the comments. DI can get really heavy on the constructor - too much boilerplate that is unnecessary and not that hard to fix if Microsoft/3rd parties wanted to fix it at the compiler/library level.
Not gonna lie, this seems really strange to me, I would question why do this when records were just created which still forces that limiting by constructor approch. I'd rather have seen a 'auto generate constructor' rather than having required property construction. Seems like a split path just to try and please everyone.
I wonder how it will work in Entity Framework. How EF will bypass such feature.
Using constructors:
```csharp
var bill = new Person
( FullName: "Bill Was"
, ...
);
```
So, if you have a long list it isn't too bad to look at. Basically it is the same as `new Person { FullName = "Bill Was" }`. Except avoiding all the constructor work with `required` would be even nicer 🙂.
Excellent video! At time mark 5:00, what are you using to draw on your screen so quickly?
it has a lot of uses where only a single constructor is needed, but if you are working on a factory type of class that gives access to different implementation based on constructor input then it obviously doesn't work
Thank you 👍🏻👍🏻
4:15 If that is "too much" for you then you should be so honest and consistent and say that object initializer blocks (that you showed before and did not object to) are even worse.
Why are they worse? Because object initializers force you to additionally specify the property name, while for methods/constructors the parameter names are optional.
And that also destroys the argument that "if there are like 10 parameters it is confusing", because you *can* simply specify the parameter names.
That also destroys the argument that a method/constructor forces you to order parameters a certain way, because as soon as you specify parameter names, you can re-order them.
Yeah, and there's also a feature in R# that shows parameter names (Inlay hints)
Great video! Thanks for the content!
I won't be using this. We already have the ability to pass variables by constructor parameter name. The code will look almost identical you just have parenthesis instead of curly braces.
var person = new Person(
FullName: "My name"
);
vs.
var person = new Person{
FullName = "My Name"
};
If in the future if you need to mark members based on some of these required members you will now have to use a constructor and broken backwards compatibility. Each instance will need to be rewritten to use the constructor.
public class Person
{
public string FullName { get; init; }
private bool IsNick { get; init; }
public Person(string FullName)
{
this.FullName = FullName;
if(this.FullName == "nick")
IsNick = true;
}
}
OFF TOPIC Question > What extension, besides Sonarlint, is good for Visual Studio, in order to check Debt Metrics, Code Complexity, etc.? Something like Stepsize Debt Metrics for VS Code...
Cool feature. Fixes the problem of constructor boilerplate and\or missing property inialization. However, the code is still too verbose. And JS\Python\Go\Other developers don't like C# for having so much "useless" code. Looks like the entire concept of properties should be reworked. I know the idea, but adding {get;set} and use it as a field looks like a trick, not like real encapsulation.
E.g. What if we had fields "init" by default? All the fields can be initialized in a constructor or object initializer and accessed only for reading (if they pulblic\internal). And if you need a public setter you add some keyword
I think C# code is verbose as it should be, surely it could be better but IMO the clarity of the code is almost instant for anyone reading.
@@diadetediotedio6918 Well, they add new features to C# itself to make it less verbose, e.g. records. If you compare C# to Kotlin, it less verbose and offers the same features
@@dimalisovyk5277
Maybe, but kotlin comes with the Java garbage and .NET environment is a different thing, so the verbosity in this case is justified because many reasons (like, Kotlin don't have pointers or low-level programming as C# when needed, C# is very old and is actually more prox from Java and/or C++ than a modern looking language like Kotlin. In Kotlin, you depend upon the JVM-compatible runtimes (yeah, I know Kotlin has a project to compile natively using LLVM, but the language features will probably not be less restrictive because the need of interoperability with JS and the JVM) and in C# the CLR is more like a framework than a runtime by itself. So I think Kotlin doesn't offer "the same features" or has the same purposes, C# has a good readability and is getting better on it, it is the tool for some jobs and Kotlin for others, there's no a silver bullet in this area.
very nice feature.
Sounds interesting, but we can't say that we won't need constructors. What if I want to encapsulate properties or class members? If I do with this approach, class inner fields must be an ''public', which brakes an Encapsulation approach, because members are visible outside of class. So, in my opinion right place to use it is DTO classes where we need to be initialized their members when we're creating its object. Thanks ;)
I would love to have this. I only wish I could dind a migration path from Framework, which doesn’t and won’t support modern C#. This is mainly a question of updating UI from WPF.
This seems like a lowering change, which means it's supported in .Net Framework. Most language changes are supported on Framework.
I only know of two things that aren't (I'm sure there are others): Default Interface Implementations, and the `with` keyword for structs. Every other thing I've tried (up to and including C# 10) works on .Net Framework 4.8
An old school approach to eliminating noisy constructors has been passing in a single class to the constructor that contained all the initial property values. I do like learning new ways to accomplish a problem. Where I work I am forced to work in .net 2.0 for the systems I work on.
Having a constructor with a long list of inputs is a design smell anyway, so it's probably better that data is being passed around in smaller classes anyway
What is the difference between the init in the property and only a get? In both cases i can only set the Property in the constructor.
Hrm. I guess that's good if you don't do any validation of constructor params. What about initializing the instance with a string.Empty or " " (Whitespace) for FullName property? Can we do validation and throw InvalidArgumentException with required/init?
What a about validation practices during object initialization? Should it go on setter then, isntead for ctor?
I personally not a fan of that approach, I would rather use "static factory method" pattern instead, then you can have a good named method that describes exactly for which purpose you create this object and if you need to create the same object maybe with other properties filled, depending on the use case.
In my own experience having multiple such factory methods have been a sign that I should really have different types for those different use cases and I was trying to jam too much into a single type.
@@bread8176 you mean like bad smell that single responsibility principal was not respected? I think it depends on how many of this methods you use, but sure this pattern can also be misused like every pattern I believe.
I really liked this feature, but I'm still think how it's gonna be for dependency injection via constructor ? It's gonna stay the same?
This functionality was really lacking before, but the option when the initialized object has fields in the constructor and required fields does not look very good 😅
Would be fantastic to have some kind of constructor or initializer method on a class or struct that runs AFTER all property initializers. So we can add logic with all the parameters already in place passed via init properties. This could be achieved by adding [init] attribute to the parameterless private constructor. Or add "init" keyword in front of it. Also, this method can be invoked by deserializers. Just a thought.
@@Eirenarch my thoughts exactly
Could you give me an example of the use case, im curious.
Indeed that's a great way to initialize objects without having to declare a constructor wherever data initialization were only needed, but saying you won't need constructors from now on or barely use them I thing is far fetched. :P Won't you still need to run other functions on initialization to prepare the new class in many cases?
Constructors already allowed for named parameters to be given. As far as I can tell the only change here is now that you can write exactly the same syntax but with curly braces instead of parentheses?
Well, with constructor you can do this: new(arg1: value1, arg2: value2, ...); you can omit the name, you can still have argument names; others have raised interesting questions, for example how does this work with reflection. To me, using an explicit constructor would be better, also esthetically it would be practically the same as new Class { args = blah }; we'll see i guess.
You can't always do so. For example in Expression trees (Linq to Sql for example, used in EF queries) this is prohibited.
true but it's also quite a special context anyway
this is pretty sweet.
Does that mean that safe generic object creation will be possible, i.e. the following will be possible and compiler enforced if IFoo has required property Bar?
public TFoo CreateFoo()
where TFoo : new(), IFoo
=> new TFoo { Bar = "Baz" };
For a second I was so excited that it could be used for DI, but alas:
> This isn't something that we have plans on doing in the default DI container. At least not for .NET 7.
Almost useless feature.
Very useful ! 🕺👍
I'm looking formward to this, wonder how well it will work with json deserialization.
Constructors are still useful in C#. For example, if I want to make a new Person object, but I want to start from a JObject that I got from a web request, it would be useful to pass that JObject in the constructor so it can convert it to a person class while assigning the necessary attributes. It's better than having a getPersonFromJObject class which is just messy and ugly.
Would it useful? Should your person class really know how it can be created from a JObject? Really? Why not have a specific static method Person.FromJObject(); that knows how to do that?
@@nickchapsas That's actually a good idea. I like it. But now I ask myself: What's better... a constructor or a static method for this use case? Thanks for responding and understanding.
@@YousefSh I'd say a constructor for things directly related to the class's properties (pass fullName to set FullName property or field) and a static method for anything custom like json
@@nickchapsas Thanks. One last question. Can we say goodbye to constructors if we need to use dependency injection?
Can you use the required keyword without the init attribute? As in you have to provide when creating the object, but you can change it later?
Are you able to "initialize" the required FullName with null or string.Empty?
I'm likely to stick with constructors. It is rare to have more than a few parameters, and it is the perfect place to verify values.
I would argue it is a bad place to verify the values actually. Should it really be the responsibility of the class itself to know what values are valid? For all the types of models? Both API contracts, Domain object and database DTOs? I'd rather have a centralised piece of code that validates instead of spreading my validation integrity which can lead to problems.
@@nickchapsas Well, taking something from DDD, you can use a Value Object for FullName and I'd say it's totally its responsibility to check valid values for its invariants like don't accept empty strings or null as internal values. Then the Person class should just validate against null FullName values, otherwise, I'd say you're having a kind of anemic domain model.
If you combine it with the field keyword (please tell me it will be in C# 11), you could do your checks in the setter before assigning the value in the backing field.
@@nickchapsas Yes - it is the class's responsibility to verify it's own data integrity. Who else knows better? Granted, a class might consult global and/or injected values to decide what values are valid, but that logic is the responsibility of the class. The old-fashioned term for this is "encapsulation".
I am indeed old-fashioned - I started learning C# in 2002, and was a C++ & Turbo Pascal programmer since 1988. So I humbly admit I may just be howling at the moon of modernity.
@@Krimog Yes, field will be included.
I'm torn on this feature. It's definitely good for readability of the code, especially outside of IDE (Pull Requests/Github etc), where you don't see what each constructor parameter actually is. But for developer experience while writing the code I see issues.
This is nice for a model with 2 properties.
Model with dozen(s) properties will be much harder to use with this feature, simply because devs will now have to discover which properties are required and must be set. Before that'd be solved with constructor that provides structured way of showing which parameters are required and which are optional.
Also I've been switching to using records for any POCO/DTO type classes anyway, and those have the opposite approach with being set via the constructors.
SO I dunno, I feel like this feature is, for now, tact on and sort of starts to interfere with other features they've been introducing. It will also largly depend on good IDE support to help with required property discovery. I'll see how it's handling in "real world" while it's released and what scenarios it becomes better than records, for example. Maybe IOptions, that do not support constructor parameter values injection? Dunno, we'll see.
You can also declare records without constructor, just like normal classes and use object initializer.
This is the comment I was looking for
I think this actually make development more precise.
Now I want a dependency keyword so that i really never need a constructor again.
Make a proposal ;-)
C# is Open Sourced