Giriş
Bugün C# ile programlama yapılırken uyulması gereken kodlama standartları ve adlandırma kurallarından bahsedeceğim. Gerek sosyal medyadan gerekse başka mecralardan öğrenci arkadaşlarımızdan gelen kodlara baktığımda kodlama standartlarına ve adlandırma kurallarına uyulmadığını hatta daha da vahim bir şekilde Türkçe karakterli adlandırmaların yapıldığını (C# derleyicisi için sorun teşkil etmez ama TR klavyeye sahip olmayan biri için sorun teşkil eder) görmekteyim. Bu sebepten Türkçe kaynak olarak bu konu hakkında fazla birşey olmadığından bu makaleyi yazma ihtiyacı duydum.
Microsoft .Net Framework yazılırken kullanılan standartlardan örnekler ile C# programlama dilinde herkesin bir bakışta anlayabileceği kod nasıl oluşturulur anlatmaya çalışalım.
Başlayalım…
Öncelikle adlandırma kuralları ile başlarsak burada bizi harflerin büyük/küçük ilişkisi ile ilgili bir kaç terim karşılamaktadır. Bunlar aşağıdaki gibidir,
lowercase | Tüm kelimelerin tüm harfleri küçük harflerden oluşur. |
UPPERCASE | Tüm kelimelerin tüm harfleri büyük harflerden oluşur. |
camelCase | İlk kelimenin tamamı küçük, devamında gelen kelimelerin ilk harfi büyük diğer harfleri küçük olur. |
PascalCase | Tüm kelimelerin ilk harfi büyük diğer harfleri küçük olur. |
Bu bilgiyi edindiğimize göre şimdi aşağıdaki tablo ile C# programlama dilinde adlandırma yaparken neleri hangi notasyon ile yazmamız gerektiğine bakalım…
Adı | Notasyon | Uzunluk | Çoğul | Önek | Sonek | Kısaltma | Altçizgi |
Class Adı | PascalCase | 128 | |||||
Constructor Adı | PascalCase | 128 | |||||
Method Adı | PascalCase | 128 | |||||
Method Argümanı | camelCase | 128 | |||||
Local Değişken | camelCase | 50 | |||||
Constants Adı | PascalCase | 50 | |||||
Field Adı | camelCase | 50 | |||||
Properties Adı | PascalCase | 50 | |||||
Delegate Adı | PascalCase | 128 | |||||
Enum Tip Adı | PascalCase | 128 |
Evet, yukarıdaki tabloda gösterildiği gibi C# programlama dilinde adlandırma kuralları bu şekildedir.
Tablodaki bazı sütunların ne anlama geldiğinden bahsedecek olursak,
Notasyon : Bir önceki tabloda bahsettiğimiz büyük/küçük harf nostasyonu
Uzunluk : Maksimum tavsiye edilen ad uzunluğu
Çoğul : Verilen ad çoğul olabilir. Örn. GetPersonal, GetPersonals
Önek : Verilen ada önekler eklenebilir. C#’ta tercih edilmemektedir. Önek dediğimizde GetirKullanıcılar daki Getir kelimesinden bahsedilmemektedir. DetaylariSiparis gibi anlam ifade eden öneklerden bahsedilmektedir.
Sonek : Aynı önekte bahsettiğimizin şeyin sonda olan halidir. Aynı örneği verirsek DetaylariSiparis yerine SiparisDetaylari şeklinde sonek kullanılmalıdır.
Kısaltma : Verilen adın kısaltılabileceği anlamındadır. Örn. btnKaydet
Altçizgi : C#’ta altçizgi kullanımı sadece private field’larda adın önünde ve event metotlarında kullanılır. Örn. _adSoyad
Şimdi de bir kaçına örnekler verelim…
Sınıf ve metot adları PascalCase yazılır :
public class ClientActivity { public void ClearStatistics() { //... } public void CalculateStatistics() { //... } }
Yukarıdaki örnekte de görebileceğiniz gibi sınıf adları PascalCase notasyonu ile öneksiz, sonek alabilen tekil olarak tanımlanmalı. Metot adları ise aynı sınıf adları gibi olup çoğul olabilmektedir.
Metot argümanları, alanlar ve lokal değişkenler camelCase yazılır :
public class Sale { int _privateField = 10; public void Add(SaleItem saleItem) { int itemCount = saleItem.Items.Count; // ... } }
Örnekte de görebileceğiniz gibi metotlara verilen argümanlar(method arguments), lokal olarak tanımlanmış değişkenler (local variables) ve sınıf içindeki tüm alanlar (field) camelCase notasyonunda yazılır.
Veri tiplerini belirtmek için adlara eklemeler yapılmamalıdır :
// Doğru kullanım int toplamDeger = 10; string mesaj = "Mesaj"; // Yanlış Kullanım int iToplamDeger = 10; string strMesaj = "Mesaj";
C#’ta veri tiplerini belirtmek için değişken adının başında önek kullanılmamalıdır. Visual Studio gibi gelişmiş IDE’ler IntelliSense özellikleri ile karışıklık yaşamamızı engellediğinden gerek duyulmaz.
Sabitler ve Salt Okunur değişkenler UPPERCASE yazılmamalıdır :
// Doğru kullanım public const string OrderStatus = "Transfered"; // Yanlış kullanım public const string ORDERSTATUS = "Transfered";
C dilinden gelen alışkanlıkların aksine Microsoft, C#’ta salt okunur ve sabitlerin PascalCase yazılmasını tavsiye etmektedir.
Değişkenler adları anlamlı seçilmeli :
// Doğru Kullanım var transferedOrders = from order in Orders where order.Status == "Transfered" select order; // Yanlış Kullanım var to = from order in Orders where order.Status == "Transfered" select order;
Örnekte de görüleceği gibi verilen değişken adları okuma kolaylığı bakımından anlamlı olmalıdır.
Kısaltmalardan kaçınılmalı :
// Doğru kullanım OrderDetail orderDetail; Permission userPermission; // Yanlış Kullanım OrderDetail ordDetail; Permission usrPermission; // İstisnalar XmlDocument xmlDocument; Uri uriWebsite;
Listede de söylediğim gibi C#’ta kısaltma kullanımı hoş görülmemektedir. Kod okunurluluğu açısından detaylı ve anlamlı adlandırma yapmak önemlidir. Bu kuralın bazı istisnaları vardır. Xml, Html, Ftp, Uri vb. gibi kısaltmalar aynen kullanılır.
Altçizgi kullanımından kaçınılmalı :
// Doğru kullanım public DateTime orderDate; public List<OrderDetail> orderDetails; // Yanlış Kullanım public DateTime order_Date; public List<OrderDetail> order_Details; // İstisnalar private DateTime _orderDate;
Örnekte de görülebileceği üzere C#’ta alt çizgi kullanımı hoş görülmemektedir. İstisna olarak private olarak tanımlanan sınıf değişkenlerinde önek olarak alt çizgi kullanılmalıdır.
Önceden tanımlı tip adlarının kullanımı (C# Alias) :
C#’ta önceden tanımlanım kısayol tip adlarının (int, double, float, string vb) kullanımında şunlara dikkat edilmelidir.
// Doğru Kullanım string name; int orderNumber; bool flag; string commaSeperatedTags = String.Join(", ", tags); int age = Int32.Parse(input); // Yanlış Kullanım String name; Int32 orderNumber; Boolean flag; string commaSeperatedTags = string.Join(", ", tags); int age = int.Parse(input);
Örnekte görülebileceği gibi tip adı olarak kısayol adlarını (int, string, bool vb.), static metot kullanımında ise .Net Framework adları (Int32, String, Boolean vb.) kullanılmalıdır.
Lokal değişkenlerde implict var kullanılmalı :
var orders = new List<Order>(); var startDate = new DateTime(2019,1,1); // İstisnalar int number = 2; string personelName; bool isActive;
Lokal değişken tanımlamalarında implict tip var keyword’ü ile tanımlama yapılmalıdır. Primitive (ilkel) tipler (int, double, float, string, bool vb) bu kuralın dışındadır.
Sınıf adlandırılmaları anlamlı olmalıdır :
public class Employee { } public class BusinessLocation { } public class DocumentCollection { }
Sınıf adlandırılmalarında bir bakışta ne anlama geldiği anlaşılacak şekilde anlamlı kelime/ler kullanılmalıdır.
Interface (arayüz) adlandırmalarında I öneki eklenmeli :
public interface IReadable { } public interface IEntity { } public interface IGroupable { }
Interface (arayüz) tanımlamalarında adın önüne I öneki eklenmeli ve PascalCase yazılmalıdır.
Namespace adlandırmaları anlamlı ve bir düzen içinde olmalı :
namespace Company.Sales.Module.SubModule { } namespace Product.Module.Component { } namespace Product.Layer.Module.Group { }
Namespace tanımalamarı bir düzen içinde temiz ve anlaşılır yazılmalıdır.
Sınıf üyesi değişken ve özellikler sınıfın en üstünde tanımlanmalı :
public class Account { public static string BankName; public static decimal Reserves; public string Number { get; set; } public DateTime DateOpened { get; set; } public DateTime DateClosed { get; set; } public decimal Balance { get; set; } // Constructor public Account() { // ... } }
Sınıf üyesi değişkenler ve özellikler (property) sınıfın en üstünde tanımlanmalıdır. Static tanımlamalar öncelikli olmalıdır.
Enum adlandırmaları tekil olmalıdır :
// Doğru Kullanım public enum Color { Red, Green, Blue, Yellow, Magenta, Cyan } // İstisnalar [Flags] public enum Dockings { None = 0, Top = 1, Right = 2, Bottom = 4, Left = 8 }
Enum adlandırılmaları tekil yapılmalıdır. İstisna olarak Flags tanımlı bit alanlı enumlar birden fazla değeri içerebileceğinden çoğul adlandırılır.
Enum tanımlarken veri tipi belirtilmemeli :
// Doğru kullanım public enum Direction { North, East, South, West } // Yanlış Kullanım public enum Direction : long { North = 1, East = 2, South = 3, West = 4 }
Enum tanımlamasında veri tipi belirtilmemelidir. İstisna olarak Flags tanımlı enumlarda veri tipi verilebilir.
Enum adlandırılmasında Enum soneki kullanılmamalı :
// Doğru Kullanım public enum Coin { Penny, Nickel, Dime, Quarter, Dollar } // Yanlış Kullanım public enum CoinEnum { Penny, Nickel, Dime, Quarter, Dollar }
Enum adlandırılmalarında Enum soneki kullanılmamalıdır.
Enum Flags adlandırmalarında Flags soneki kullanılmamalıdır :
// Doğru Kullanım [Flags] public enum Dockings { None = 0, Top = 1, Right = 2, Bottom = 4, Left = 8 } // Yanlış Kullanım [Flags] public enum DockingsFlags { None = 0, Top = 1, Right = 2, Bottom = 4, Left = 8 }
Enum Flags adlandırılmalarında Flags soneki kullanılmamalıdır.
Olay bilgilerini taşıyacak sınıf adlandırılmasında EventArgs soneki kullanılmalı :
public class BarcodeReadEventArgs : System.EventArgs { }
Event hakkında bilgi taşıyan EventArgs sınıflarının adlandırılmasında EventArgs soneki okuma esnasında kolaylık sağlayacaktır.
Olay işleyicilerinin adlandırılmasında EventHandler soneki kullanılmalı :
public delegate void ReadBarcodeEventHandler(object sender, ReadBarcodeEventArgs e);
Olay işleyicilerin (Event Handler) adlandırılmasında EventHandler soneki okuma esnasında kolaylık sağlayacaktır.
Büyük/küçük harf farkından başka farkı olamayacak şekilde metot argümanı adlandırması yapılmamalı :
private void MyFunction(string name, string Name) { //... }
Bir metota verilen argüman adları birbirinden farklı olmalıdır. Yukarıdaki örnek derleyici tarafından sorunsuz işlenecektir. (C# case-sensitive bir dildir.) Fakat okurken iki değişken rahatlıkla karıştırılabilir.
Olay işleyici tanımlarken en az iki argüman eklenmelidir :
public void ReadBarcodeEventHandler(object sender, ReadBarcodeEventArgs e) { //... }
Olay işleyici tanımanırken en az iki argüman tanımlanmalıdır. İlk argüman sender adında object tipli olayı tetikleyen nesneyi taşır, ikinci argümanda olay ile ilgili bilgileri taşımaktadır.
İstisna adlandırırken Exception soneki kullanılmalıdır :
public class BarcodeReadException : System.Exception { }
İstisna adlandırması yapılırken Exception soneki okuma esnasında kolaylık sağlayacaktır.
Tek satır dönüşlerde Expression Body kullanılmalıdır :
// Doğru Kullanım public ActionResult Dashboard() => View(); // Yanlış Kullanım public ActionResult Dashboard() { return View(); }
Tek satır dönüşlerinde (metot, özellik vb) Expression Body (=>) kullanılması okuma esnasında kolaylık sağlayacaktır.
String boş yada null kontrolü :
// Doğru Kullanım var varName = "muzaffer"; if (!String.IsNullOrEmpty(varName)) { //code } // Yanlış Kullanım var varName = "muzaffer"; if (varName != null && varName != "") { //code }
String.IsNullOrEmpty kullanılmalıdır.
?? ile null kontrolü :
Test test = new Test(); // Doğru Kullanım var varName = test.Name ?? ""; // Yanlış Kullanım var varName = test.Name != null ? test.Name : ""; // Tek satır if kullanımı
?? (coalescing expression) ile null kontrolü çok daha pratiktir.
Nesne başlatıcı kullanımı :
// Doğru Kullanım var test = new Test { Id = 1, Name = "muzaffer" }; // Yanlış Kullanım Test test = new Test(); test.Id = 1; test.Name = "muzaffer";
Bir nesne oluştururken nesne içindeki özelliklere (property) tanımlama yapmak için mümkünse nesne başlatıcı (object initializer) kullanmak daha verimlidir.
?. operatörü kullanımı :
// Doğru Kullanım var empName = ""; Session["Name"] = "Muzaffer AKYIL"; empName = Session["Name"]?.ToString() ?? ""; // Yanlış Kullanım var empName = ""; Session["Name"] = "Muzaffer AKYIL"; if (Session["Name"] != null) { empName = Session["Name"].ToString(); } else { empName = ""; }
Yukarıdaki örnekte de görüneceği üzere ?. operatörü ile null kontrolü yapıp ?? ile dönen değerin null olup olmadığında bakıp eğer null değilse atanır eğer null ise “” (string.Empty) atanır. Burada dikkat edilmesi gereken şey Session dizisinin Name elemanı yoksa normal şartlarda ToString metodu exception fırlatacaktır. ?. operatörü sayesinde Name elemanı yoksa ToString çalıştırılmadan null dönülür. Hemen peşinden yaptığımız ver bir kaç üstteki örnekte gördüğümüz ?? ifadesi ile null olup olmadığı kontrol edilir ve null değilse atama null ise ?? yanındaki atanır.
Tek satırlık ifadelerde blok parantezi kullanılmamalı :
var count = 10; // Doğru Kullanım if (count > 0) count++; //code // Yanlış Kullanım if (count > 0) { //code count++; } // Doğru Kullanım for (int i = 0; i < count; i++) count += 10; // Yanlış Kullanım for (int i = 0; i < count; i++) { //code count += 10; } // var testList = new List<Test>(); var names = new ArrayList(); // Doğru Kullanım foreach (var item in testList) names.Add(item.Name); // Yanlış Kullanım foreach (var item in testList) { names.Add(item.Name); }
Tek satırlık ifadelerin yazıldığı durumlarda blok parantezleri kullanılmaması okuma kolaylığı açısından faydalıdır.
String interpolasyon kullanılmalıdır :
Test test = new Test(); // Doğru Kullanım var details = $"{test.Name}, you are welcome, Your Id is {test.Id}_emp"; // Yanlış Kullanım var details = string.Format("{0}, you are welcome, Your Id is {1}", test.Name , test.Id + "_emp");
String.Format yerine string interpolasyon ($””) kullanarak daha okunaklı string birleştirmeleri yapılabilir.
region kullanımı ile düzen sağlama :
public class Test { #region ctor public void Test() { } #endregion #region fields public int number; public string text; #endregion #region methods public void AddTest(int number, string text) { } public bool RemoveTest(int number) { } #endregion }
Yukarıda da görüleceği gibi region keyword’ü ile kodumuzu düzene sokabilir ve aradığımızı daha hızlı bulabiliriz.
Bititrirken…
Evet arkadaşlar, C# programlama dilinin kimisi yazılı kimisi yazılı olmayan bazı kural ve düzenlerinden bahsettik. Son olarakta genel .Net Framework standart kontrollerinin isimlerinin nasıl kısaltılması gerektiği ile ilgili bir liste paylaşalım.
Kısaltma | Kontrol Adı |
btn | Button |
cb | CheckBox |
cbl | CheckBoxList |
ddl | DropDownList |
fu | FileUpload |
hdn | HiddenField |
hlk | Hyperlink |
img | Image |
lbl | Label |
lbtn | LinkButton |
mv | MultiView |
pnl | Panel |
txt | TextBox |
dtg | DataGrid |
imb | ImageButton |
lst | ListBox |
dtl | DataList |
rep | Repeater |
rdo | RadioButton |
rdl | RadioButtonList |
phd | Placeholder |
tbl | Table |
gv | GridView |
dtv | DetailView |
fv | FormView |
Teşekkürler Çok Güzel anlatım
Çok güzel bir makale ve bir okadar güzel anlatım.
Temiz ve açıklayıcı anlatım. Teşekkürler