C# Kodlama Standartları, Adlandırma Kuralları ve İpuçları

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.

Ufak bir not
Malesef yazılımın dili küresel olarak İngilizce olduğundan örneklerimizde İngilizce olacaktır. Gerek standartlar gereği, gerekse kullandığımız bazı mimarilerin (Örn. EntityFramework) pluralization (çoğullaştırma) işlemleri için İngilizce adlandırma önem kazanmaktadır.

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,

lowercaseTüm kelimelerin tüm harfleri küçük harflerden oluşur.
UPPERCASETü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.
PascalCaseTü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ıNotasyonUzunlukÇoğulÖnekSonekKısaltmaAltçizgi
Class AdıPascalCase128
Constructor AdıPascalCase128
Method AdıPascalCase128
Method ArgümanıcamelCase128
Local DeğişkencamelCase50
Constants AdıPascalCase50
Field AdıcamelCase50
Properties AdıPascalCase50
Delegate AdıPascalCase128
Enum Tip AdıPascalCase128

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ısaltmaKontrol Adı
btnButton
cbCheckBox
cblCheckBoxList
ddlDropDownList
fuFileUpload
hdnHiddenField
hlkHyperlink
imgImage
lblLabel
lbtnLinkButton
mvMultiView
pnlPanel
txtTextBox
dtgDataGrid
imbImageButton
lstListBox
dtlDataList
repRepeater
rdoRadioButton
rdlRadioButtonList
phdPlaceholder
tblTable
gvGridView
dtvDetailView
fvFormView

Kaynakça ve ileri okuma

3 thoughts to “C# Kodlama Standartları, Adlandırma Kuralları ve İpuçları”

Bir Cevap Yazın

Bu site, istenmeyenleri azaltmak için Akismet kullanıyor. Yorum verilerinizin nasıl işlendiği hakkında daha fazla bilgi edinin.