docs
docs copied to clipboard
Should the console project template use top-level statements
For .NET 6, the console project template was changed to use top-level statements. The code that is created in Program.cs is:
// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");
In earlier versions of .NET and .NET Core, the code that is created in Program.cs is:
using System;
using System.Collections.Generic;
using System.Linq;
namespace MyApp // Note: actual namespace depends on the project name.
{
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
}
Discussion about whether this was a good change began in https://github.com/dotnet/docs/issues/26313 but there was some confusion about what exactly the various up or down votes applied to. This issue provides comments to vote on that clearly describe the options.
Up-vote this comment if you support the use of top-level statements in project templates.
Up-vote this comment if you prefer project templates to use the code created in previous .NET versions.
Up-vote this comment if you would like to be given a choice between top-level statements code and the code created in previous .NET versions.
I'm sorry in advance, but what about ASP.NET Core templates like -webapi
?
I'd like to have choice between normal Startup.cs and Program.cs
vs new Program.cs
what about ASP.NET Core templates like
-webapi
? I'd like to have choice between normalStartup.cs and Program.cs
vs newProgram.cs
@Rick-Anderson do you want to create a discussion issue like this one in the ASP.NET Core repo?
I'm sorry in advance, but what about ASP.NET Core templates like
-webapi
? I'd like to have choice between normalStartup.cs and Program.cs
vs newProgram.cs
Use the ASP.NET Core 5 templates. Startup is fully supported.
Use the ASP.NET Core 5 templates. Startup is fully supported.
That is only temporary as those templates will be removed once .net core 5 is out of support. So, no, that is not a valid permanent solution to the problem.
The templates are not removed when .NET Core 5 goes out of support.
The templates are not removed when .NET Core 5 goes out of support.
@Rick-Anderson can I create .NET Framework 4.5.1 template in VS 2022? Will I be able to create .NET Core 5 template in VS 2030? I don't think so. We want to make sure that the old-style explicit templates will be available in the future as well as the new one.
https://dotnet.microsoft.com/download/dotnet/1.1 is the .NET 1.1 SDK. Download that and you can create the ASP.NET Core 1.1 templates with VS 2022.
If you have complicated startup logic, you might want to keep using startup. But with complicated startup logic, the templates aren't much help.
But with complicated startup logic, the templates aren't much help.
@Rick-Anderson If you think that you are right, then people will also support your opinion. Organize a vote and the question will be closed.
In my opinion, the move to remove clutter is a very good one. I was also quite shocked when I first saw it, but when I teach coding to newcomers, it makes things so much easier. No more "just ignore all that stuff and focus on the things between the {}".
In general it's a very good direction follow, as long as there's no hidden functionality ("magic defaults"). With that I mean hidden behavior, for example implicit Console.Foo()
statements that are executed if we use top-level statements, but aren't if we use the explicitly defined approach. If it's just things that get in the way, and add no value, remove it. What would be valuable would be a good way with tooling to 'escalate' to the cluttered view again if it's needed.
@tdykstra thanks for starting this issue
as long as there's no hidden functionality ("magic defaults")
But there is magic going on. The signature of the program's entry-point method is deduced from your code. The only way to control it, is by changing your code (using await and return statements) since it's magically generated on-the-fly by the compiler. The relevant magic can be found at https://github.com/dotnet/roslyn/blob/main/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedSimpleProgramEntryPointSymbol.cs#L37
So, no, it doesn't get in the way and yes, it does add value. It makes the method signature explicit and it makes the syntax consistent with any other cs file. The idea of 'less is more' does not apply here, imho.
What used to be consistent by default, no longer is, by making namespace, class and method implicit. So, indeed, there are no more implicit Console.Foo()
lines, which is a good thing, but now there is new implicit code/magic.
Keeping cs file syntax consistent over all files and learning the concept of classes and namespaces (which they would have to learn anyway at some point) seems an easier thing to understand for newcomers than compilers generating those classes and namespaces on-the-fly. I can see their questions like "Why is the syntax of Program.cs
different from all the other files?" Answer: because the compiler can do magic.
In short, I think that syntax consistency wins easily over lines of code.
BTW, can we have a MVC version Identity ? After ASP.NET Core 2.1 Identity only provider as Razor pages and it was hard to customize, unless .NET team only doing "Hello World" level project, or only provide Razor version Identity was not smart move, like this "top-level statements" issue.
And .NET team only close issue to close our voice like #24181
BTW, can we have a MVC version Identity ? After ASP.NET Core 2.1 Identity only provider as Razor pages and it was hard to customize, unless .NET team only doing "Hello World" level project, or only provide Razor version Identity was not smart move, like this "top-level statements" issue.
And .NET team only close issue to close our voice like #24181
Since that happened I/we tend to just do it manualy. Eg. create our own views and models and add the service injections. I/We also have abstracted the (User/Role/etc)-Manager using our own interfaces and implementations. So we just add my/our own library in my/our projects.
No more "just ignore all that stuff and focus on the things between the {}".
IMHO if this is the style of teaching then the teaching needs to be fixed. Namespaces and class declarations aren't to be ignored but understood. Coding classes should start of with conceptual lessons (such as "what are classes?") before ever writing code. Especially with a language like C# where everything is object oriented. Without that foundation the differences between Console.Write()
and objA.Write()
would be confusing ("Why doesn't Console
require new
?").
For new students it might be sufficient to explain that it's a class declaration and that they would be explored more fully later. The new templates just abstract everything away to background magic and, as others have mentioned, make it even more confusing to understand why Program.cs
behaves differently.
Also see this comment https://github.com/dotnet/docs/issues/26313#issuecomment-973971021 for good examples.
This is too much abstraction away from the core. What if I wanted to use the async version? I have to create a .net 5 project and alter it. This is going a bit too far.
@syntechtix Top-level statements support await
.
Bring old template back to net 6!
I see zero sense in abstracting main this heavily, please change it back and please don't let whoever made this decision make others.
The only possible use I can find for this is quick testing but that's what vscode is for.
is synthetic sugar of hiding 12 lines of code worth these?
- implicitly defined string[] args
- implicitly defined using directives
- fixed Main method signature
- no backward compatibility of program enterance code
- confuses programmers
In my opinion, the move to remove clutter is a very good one. I was also quite shocked when I first saw it, but when I teach coding to newcomers, it makes things so much easier. No more "just ignore all that stuff and focus on the things between the {}".
In general it's a very good direction follow, as long as there's no hidden functionality ("magic defaults"). With that I mean hidden behavior, for example implicit
Console.Foo()
statements that are executed if we use top-level statements, but aren't if we use the explicitly defined approach. If it's just things that get in the way, and add no value, remove it. What would be valuable would be a good way with tooling to 'escalate' to the cluttered view again if it's needed.
I'm sorry what are you ignoring in C#? Yeah namespaces are not super necessary all the time but you need main, you need your inclusions. What if you need to make main async? What libraries are in use? What libraries do you need? Where do you put out of main methods?
I honestly and truly worry about your teaching style if you jump right past includes and main and namespaces.
Yeah, in not a huge fan of the new template. But I'm now over 40, so maybe old man complaining here. 🤔
Zzzzz
Yeah, in not a huge fan of the new template. But I'm now over 40, so maybe old man complaining here. 🤔
Zzzzz
If it helps I'm 27.
@brogdogg I'm 52 (taught C# and developing all day long) and I'm complaining a LOT!
I personally don't like this change, because it creates more confusion. I'm reliant on the backwards compatibility.
It compiles flawlessly. However, I need the old design back.
Keep it!
At first, I was surprised, too. Then I looked at the compiler code. Turns out, if you want to have a return value, you can add the return
keyword and a value as the last statement. Or, if you just feel like writing return
because you like the warm and fuzzy feeling you get, go for it, it works! If you want the program to run asynchronously, you can add the await
keyword in front of an asynchronous statement. Also, if you need to write a using statement, you write using <libraryname>;
.
The concept of this being magic is more along the lines of this being more magical than having to write all of the boilerplate code. The compiler is magic.
As far as teaching new coders how to code, this is valuable. Imagine writing "Hello World" in exactly one line of code! It also makes you think, "Do I really need to include System
and its friends at the top of every class?"
The Main
method should be the most boring method in your program. It is the entry point, not the "let's cram everything this program can do between these two brackets" point. Since OOP is about Os, why not create a class that encompasses the functionality of your P.
Also, I'm not punch cards and mainframes, but I'm also not new school. I think it is okay to have your cheese moved once in a while. It makes you a better programmer.
Keep it!
...
Also, I'm not punch cards and mainframes, but I'm also not new school. I think it is okay to have your cheese moved once in a while. It makes you a better programmer.
The debate isn't so much about keeping the feature as it is about what the default template looks like. Sure, the feature has its place and few are truly debating that (being able to run an MSDN example without all the extra boilerplate is a big plus, for example). But outside of super basic examples, this feature generally hinders and confuses. Real world situations call for more fine-tuned control and, therefore, require reverting back to the non-top level statement template.
Hence the request for an option for those that want to use the new template. That way everyone will be happy. Those who want the old style can use it while those that don't won't be forced to use hackery and workarounds.
Keep it! ... Also, I'm not punch cards and mainframes, but I'm also not new school. I think it is okay to have your cheese moved once in a while. It makes you a better programmer.
The debate isn't so much about keeping the feature as it is about what the default template looks like. Sure, the feature has its place and few are truly debating that (being able to run an MSDN example without all the extra boilerplate is a big plus, for example). But outside of super basic examples, this feature generally hinders and confuses. Real world situations call for more fine-tuned control and, therefore, require reverting back to the non-top level statement template.
Hence the request for an option for those that want to use the new template. That way everyone will be happy. Those who want the old style can use it while those that don't won't be forced to use hackery and workarounds.
I disagree. Why would they keep a feature that no one wants or uses? There would be no need for this thread if it were as simple as adding a checkbox.
I'm not sure what real-world situations would require you to type out the Main
method, but I am curious.
In addition, it may be a hinderance or confusing for some, but as I said previously, the entry point is a place where the program starts. If you have a class that runs your application, say, for example TestClass
with an async method, you can write this:
TestNewTemplate.TestClass tc = new();
await tc.TestAsyncFunctionality(args[]);
Or:
using TestNewTemplate;
TestClass tc = new();
int result = await tc.TestAsyncFunctionality(args[]);
return result;
Or make it static:
return await TestNewTemplate.TestClass.TestAsyncFunctionality(args[]);