Foto oleh Jorge Jesus via Pexels

Setiap program C# memiliki struktur dasar yang konsisten: dimulai dari namespace sebagai pengelompokan logis kode, class sebagai wadah utama, dan method Main sebagai titik masuk (entry point) yang pertama kali dijalankan ketika program dieksekusi.

Memahami struktur ini bukan sekadar menghafal urutan penulisan, tetapi memahami mengapa setiap bagian diperlukan: namespace mencegah tabrakan nama antar library berbeda, class mengelompokkan data dan perilaku terkait, dan method Main memberi titik awal yang jelas bagi runtime untuk mulai mengeksekusi kode.

Artikel ini membedah struktur dasar program C# baris demi baris, termasuk perbedaan gaya penulisan top-level statements yang diperkenalkan pada versi C# modern dibanding gaya tradisional dengan Main method eksplisit.

Struktur Program Tradisional dengan Main Method

Struktur lengkap program C# gaya tradisional

using System; namespace AplikasiSaya { class Program { static void Main(string[] args) { Console.WriteLine("Halo Dunia"); } } }
Pada gaya tradisional, setiap elemen ditulis secara eksplisit: direktif using untuk mengimpor namespace yang dibutuhkan, deklarasi namespace untuk mengelompokkan kode, class Program sebagai wadah, dan method Main static sebagai titik masuk yang dipanggil otomatis oleh CLR saat program dijalankan.

Top-Level Statements pada C# Modern

Top-level statements menghilangkan boilerplate

// Program.cs (C# 10 ke atas) Console.WriteLine("Halo Dunia"); // Setara persis dengan struktur tradisional di atas, // namun boilerplate class dan Main disembunyikan compiler
Sejak C# 9, Microsoft memperkenalkan top-level statements yang memungkinkan kode ditulis langsung tanpa perlu mendeklarasikan class dan method Main secara eksplisit, sangat cocok untuk program sederhana atau untuk mengurangi boilerplate pada project baru, meski di balik layar compiler tetap membungkusnya menjadi struktur yang sama.

Parameter args pada Method Main

Parameter args menampung argumen command line

static void Main(string[] args) { if (args.Length > 0) { Console.WriteLine($"Argumen pertama: {args[0]}"); } } // Dijalankan dari command line: dotnet run -- halo // Expected output: Argumen pertama: halo
Parameter args pada method Main menampung argumen yang dikirim dari command line saat program dijalankan, memungkinkan program menerima input konfigurasi tanpa perlu meminta input interaktif, sebuah pola yang umum dipakai pada aplikasi console dan tools command-line.

Namespace untuk Mengorganisasi Kode Berskala Besar

Namespace berbeda mencegah tabrakan nama class

namespace TokoOnline.Models { public class Produk { public string Nama { get; set; } } } namespace TokoOnline.Services { public class ProdukService { /* ... */ } }
Pada project berskala besar dengan ratusan file, namespace membantu mengelompokkan class berdasarkan fungsinya (misalnya Models, Services, Controllers) sekaligus mencegah konflik penamaan jika dua class kebetulan memiliki nama yang sama namun berada di namespace berbeda, karena keduanya tetap dianggap entitas yang terpisah oleh compiler.

Pada akhirnya, baik gaya tradisional maupun top-level statements menghasilkan program yang berjalan identik di level Intermediate Language setelah dikompilasi, sehingga pemilihan keduanya lebih merupakan soal gaya penulisan dan kebutuhan keterbacaan tim, bukan perbedaan performa saat program dijalankan.

Namespace dan Aturan Penataan Kode dalam Satu Proyek C#

Struktur namespace memisahkan kode berdasarkan modul/domain

namespace MpmFinance.Billing { public class InvoiceService { public decimal HitungTotal(decimal subtotal, decimal pajak) { return subtotal + (subtotal * pajak); } } } // Pemakaian dari file lain: using MpmFinance.Billing; var service = new InvoiceService(); Console.WriteLine(service.HitungTotal(100000, 0.11m)); // Output: 111000

Namespace berfungsi sebagai mekanisme pengelompokan logis untuk class, struct, interface, dan tipe lainnya agar tidak terjadi bentrok nama ketika proyek berkembang menjadi besar atau ketika menggabungkan beberapa library pihak ketiga. Dengan menuliskan class InvoiceService di dalam namespace MpmFinance.Billing, class tersebut hanya bisa diakses dengan nama penuh MpmFinance.Billing.InvoiceService kecuali file lain menambahkan pernyataan using di bagian atas kode.

Sejak C# 10, Microsoft memperkenalkan file-scoped namespace yang memungkinkan penulisan namespace MpmFinance.Billing; tanpa tanda kurung kurawal, sehingga seluruh isi file otomatis berada dalam namespace tersebut dan mengurangi satu level indentasi. Gaya penamaan namespace yang umum dipakai mengikuti pola NamaPerusahaan.NamaProduk.NamaModul, sehingga struktur folder proyek biasanya mencerminkan struktur namespace secara langsung.

Penataan namespace yang konsisten juga mempermudah proses refactoring dan code review karena setiap developer dapat menebak lokasi suatu class hanya dari nama namespace-nya. Pada proyek skala tim, kesepakatan konvensi namespace sejak awal mencegah terjadinya duplikasi struktur folder yang berantakan ketika jumlah modul bertambah seiring waktu.

Partial Class untuk Memecah Definisi Class ke Beberapa File

Satu class Pegawai didefinisikan di dua file terpisah menggunakan kata kunci partial

// File: Pegawai.Data.cs public partial class Pegawai { public string Nama { get; set; } = ""; public decimal Gaji { get; set; } } // File: Pegawai.Logic.cs public partial class Pegawai { public decimal HitungBonus() => Gaji * 0.1m; } var pegawai = new Pegawai { Nama = "Dewi", Gaji = 6000000 }; Console.WriteLine(pegawai.HitungBonus()); // Output: 600000

Kata kunci partial memungkinkan definisi sebuah class, struct, atau interface dipecah menjadi beberapa file fisik yang berbeda, namun tetap diperlakukan compiler sebagai satu tipe tunggal setelah proses kompilasi selesai. Pada contoh di atas, class Pegawai memiliki property di file Pegawai.Data.cs dan method di file Pegawai.Logic.cs, namun keduanya digabung menjadi satu class utuh yang bisa diakses melalui satu instance saja tanpa perbedaan perilaku dibanding jika ditulis dalam satu file.

Penggunaan partial class paling umum dijumpai pada kode hasil generate otomatis oleh tooling, misalnya designer file pada Windows Forms atau kode hasil scaffolding Entity Framework, di mana bagian yang digenerate otomatis dipisahkan dari bagian yang ditulis manual oleh developer agar proses regenerasi kode tidak menimpa perubahan manual yang sudah dilakukan sebelumnya. Setiap kali designer memperbarui UI, hanya file partial tertentu yang ditulis ulang tanpa menyentuh file logika bisnis.

Selain partial class, C# juga mengenal partial method yang dideklarasikan di satu bagian partial class tanpa implementasi dan boleh diimplementasikan di bagian partial lainnya, atau dibiarkan tanpa implementasi sama sekali sehingga compiler akan menghapus seluruh pemanggilannya tanpa error. Semua bagian partial dari satu tipe harus memiliki modifier aksesibilitas yang sama dan berada dalam namespace serta assembly yang identik agar dapat digabungkan dengan benar oleh compiler, dan percobaan menuliskan modifier yang berbeda di antara bagian-bagiannya akan langsung ditolak.

Global Using dan Implicit Usings untuk Menyederhanakan Program

// GlobalUsings.cs global using System; global using System.Collections.Generic; global using System.Linq; // Program.cs - tidak perlu menulis using di setiap file var angka = new List<int> { 3, 1, 4, 1, 5 }; Console.WriteLine(string.Join(",", angka.OrderBy(x => x))); // Output: // 1,1,3,4,5

Fitur global using memungkinkan satu direktif using berlaku untuk seluruh file dalam project, cukup dideklarasikan sekali dengan awalan kata global pada salah satu file, umumnya diberi nama GlobalUsings.cs agar mudah ditemukan. Hal ini mengurangi pengulangan baris using yang sama di setiap file .cs, terutama pada project besar dengan puluhan file dan banyak namespace yang sering dipakai bersama seperti System.Linq atau System.Collections.Generic, sehingga setiap file baru tidak perlu lagi dibuka dengan daftar using yang panjang di bagian atas.

Selain itu, project SDK modern menyediakan opsi ImplicitUsings pada file .csproj yang otomatis menyertakan namespace umum seperti System dan System.Linq tanpa perlu dideklarasikan sama sekali, cukup dengan mengaktifkan enable. Kombinasi global using dan implicit usings membuat file kode menjadi jauh lebih ringkas dan fokus pada logika, namun tim tetap perlu mendokumentasikan namespace apa saja yang aktif secara implisit agar tidak membingungkan anggota baru yang belum terbiasa dengan konvensi project tersebut.

Kesalahan Umum yang Sering Terjadi

Lupa Menambahkan using Statement yang Dibutuhkan

Memakai kelas dari namespace tertentu tanpa menambahkan direktif using yang sesuai akan menghasilkan error kompilasi 'the type or namespace could not be found', meski kelas tersebut sebenarnya ada di library yang sudah terpasang.

Mencampur Gaya Top-Level Statements dengan Class Program Eksplisit

Satu project tidak boleh memiliki top-level statements di Program.cs sekaligus deklarasi class Program dengan method Main secara eksplisit di file lain, karena compiler akan bingung menentukan mana titik masuk sebenarnya.

Menaruh Semua Kode dalam Satu Namespace Tanpa Struktur

Project besar yang tidak memecah kodenya ke dalam namespace yang bermakna akan sulit dinavigasi, terutama saat jumlah file sudah mencapai puluhan atau ratusan.

Kapan Pendekatan Ini Tidak Cocok Dipakai

Top-level statements memberikan kode yang lebih ringkas untuk program kecil atau skrip sederhana, namun untuk aplikasi production berskala besar, struktur eksplisit dengan namespace dan class yang jelas tetap lebih disarankan karena lebih mudah dinavigasi oleh banyak developer.

Mengelompokkan kode dalam banyak namespace memberikan organisasi yang rapi, namun terlalu banyak pemecahan namespace untuk project kecil justru bisa menambah kompleksitas yang tidak perlu dibanding manfaat yang didapat.

Ringkasan

Struktur dasar program C# terdiri dari namespace, class, dan method Main sebagai titik masuk, dengan top-level statements sebagai alternatif modern yang lebih ringkas untuk kode sederhana. Memahami kedua gaya ini penting karena keduanya akan sering ditemui, baik pada tutorial lama maupun project baru yang memakai fitur C# terkini.