Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Nota
Artikel ini adalah spesifikasi fitur. Spesifikasi berfungsi sebagai dokumen desain untuk fitur tersebut. Ini termasuk perubahan spesifikasi yang diusulkan, bersama dengan informasi yang diperlukan selama desain dan pengembangan fitur. Artikel ini diterbitkan sampai perubahan spesifikasi yang diusulkan diselesaikan dan dimasukkan dalam spesifikasi ECMA saat ini.
Mungkin ada beberapa perbedaan antara spesifikasi fitur dan implementasi yang selesai. Perbedaan tersebut diperoleh dalam catatan terkait rapat desain bahasa (LDM) .
Anda dapat mempelajari lebih lanjut tentang proses untuk mengadopsi speklet fitur ke dalam standar bahasa C# dalam artikel tentang spesifikasi .
Masalah utama: https://github.com/dotnet/csharplang/issues/2765
Ringkasan
Izinkan urutan pernyataan terjadi tepat sebelum namespace_member_declarationdari compilation_unit (yaitu file sumber).
Semantiknya adalah bahwa jika urutan pernyataan seperti itu ada, deklarasi jenis berikut, modulo nama metode aktual, akan dipancarkan:
partial class Program
{
static async Task Main(string[] args)
{
// statements
}
}
Lihat juga https://github.com/dotnet/csharplang/issues/3117.
Motivasi
Ada sejumlah boilerplate yang mengelilingi bahkan program paling sederhana, karena kebutuhan akan metode Main eksplisit. Ini tampaknya menghalangi pembelajaran bahasa dan kejelasan program. Oleh karena itu, tujuan utama fitur ini adalah untuk memungkinkan penyusunan program C# tanpa boilerplate yang tidak perlu, untuk kepentingan pelajar dan kejelasan kode.
Desain terperinci
Sintaksis
Satu-satunya sintaks tambahan adalah mengizinkan urutan pernyataan-pernyataan dalam unit kompilasi, tepat sebelum deklarasi_anggota_namespace .
compilation_unit
: extern_alias_directive* using_directive* global_attributes? statement* namespace_member_declaration*
;
Hanya satu compilation_unit yang diizinkan untuk memiliki pernyataan .
Contoh:
if (args.Length == 0
|| !int.TryParse(args[0], out int n)
|| n < 0) return;
Console.WriteLine(Fib(n).curr);
(int curr, int prev) Fib(int i)
{
if (i == 0) return (1, 0);
var (curr, prev) = Fib(i - 1);
return (curr + prev, curr);
}
Semantik
Jika ada pernyataan tingkat atas di unit kompilasi mana pun dari program, maknanya seolah-olah digabung dalam tubuh blok metode Main dari kelas Program di namespace global, sebagai berikut:
partial class Program
{
static async Task Main(string[] args)
{
// statements
}
}
Jenisnya bernama "Program", sehingga dapat dirujuk berdasarkan nama dari kode sumber. Ini adalah jenis parsial, sehingga jenis bernama "Program" dalam kode sumber juga harus dinyatakan sebagai parsial.
Tetapi nama metode "Main" hanya digunakan untuk tujuan ilustrasi, nama aktual yang digunakan oleh kompilator bergantung pada implementasi dan metode tidak dapat dirujuk berdasarkan nama dari kode sumber.
Metode ini ditetapkan sebagai titik masuk program. Metode yang dideklarasikan secara eksplisit yang menurut konvensi dapat dianggap sebagai kandidat titik masuk diabaikan. Peringatan akan dilaporkan ketika itu terjadi. Dimungkinkan untuk menentukan titik masuk yang berbeda melalui -main:<type> sakelar kompiler.
Metode titik masuk selalu memiliki satu parameter formal, string[] args. Lingkungan eksekusi membuat dan meneruskan argumen string[] yang berisi argumen baris perintah yang ditentukan saat aplikasi dimulai. Argumen string[] tidak pernah null, tetapi mungkin memiliki panjang nol jika tidak ada argumen baris perintah yang ditentukan. Parameter 'args' berada dalam cakupan dalam pernyataan tingkat atas dan tidak berada dalam cakupan di luarnya. Aturan konflik/bayangan nama reguler berlaku.
Operasi asinkron diizinkan dalam pernyataan pada tingkat atas sejauh diizinkan dalam pernyataan di dalam metode titik masuk asinkron biasa. Namun, mereka tidak diperlukan, jika ekspresi await dan operasi asinkron lainnya dihilangkan, tidak ada peringatan yang dihasilkan.
Tanda tangan metode titik masuk yang dihasilkan ditentukan berdasarkan operasi yang digunakan oleh pernyataan tingkat atas sebagai berikut:
| Async-operations\Return-with-expression | Hadirkan | Absen |
|---|---|---|
| Hadirkan | static Task<int> Main(string[] args) |
static Task Main(string[] args) |
| Absen | static int Main(string[] args) |
static void Main(string[] args) |
Contoh di atas akan menghasilkan deklarasi metode $Main berikut:
partial class Program
{
static void $Main(string[] args)
{
if (args.Length == 0
|| !int.TryParse(args[0], out int n)
|| n < 0) return;
Console.WriteLine(Fib(n).curr);
(int curr, int prev) Fib(int i)
{
if (i == 0) return (1, 0);
var (curr, prev) = Fib(i - 1);
return (curr + prev, curr);
}
}
}
Pada saat yang sama contoh seperti ini:
await System.Threading.Tasks.Task.Delay(1000);
System.Console.WriteLine("Hi!");
akan menghasilkan:
partial class Program
{
static async Task $Main(string[] args)
{
await System.Threading.Tasks.Task.Delay(1000);
System.Console.WriteLine("Hi!");
}
}
Contoh seperti ini:
await System.Threading.Tasks.Task.Delay(1000);
System.Console.WriteLine("Hi!");
return 0;
akan menghasilkan:
partial class Program
{
static async Task<int> $Main(string[] args)
{
await System.Threading.Tasks.Task.Delay(1000);
System.Console.WriteLine("Hi!");
return 0;
}
}
Dan contoh seperti ini:
System.Console.WriteLine("Hi!");
return 2;
akan menghasilkan:
partial class Program
{
static int $Main(string[] args)
{
System.Console.WriteLine("Hi!");
return 2;
}
}
Cakupan variabel lokal tingkat atas dan fungsi lokal
Meskipun variabel dan fungsi lokal tingkat atas "dibungkus" ke dalam metode titik masuk yang dihasilkan, variabel dan fungsi tersebut masih harus berada dalam cakupan di seluruh program di setiap unit kompilasi. Untuk keperluan evaluasi nama secara sederhana, setelah namespace global tercapai:
- Pertama, upaya dilakukan untuk mengevaluasi nama dalam metode jalur masuk yang dihasilkan dan hanya jika upaya ini tidak berhasil
- Evaluasi "reguler" dalam deklarasi namespace global dilakukan.
Ini dapat menyebabkan penutupan nama-nama namespace dan tipe yang dideklarasikan dalam namespace global serta nama-nama yang diimpor.
Jika evaluasi nama sederhana terjadi di luar pernyataan tingkat atas dan evaluasi menghasilkan variabel atau fungsi lokal tingkat atas, yang akan menyebabkan kesalahan.
Dengan cara ini kami melindungi kemampuan kami di masa depan untuk mengatasi "Fungsi tingkat atas" dengan lebih baik (skenario 2 dalam https://github.com/dotnet/csharplang/issues/3117), dan dapat memberikan diagnosis yang berguna kepada pengguna yang secara keliru percaya bahwa fungsi tersebut didukung.
C# feature specifications