Yaygın C# kod kuralları
Kodlama kuralları, bir geliştirme ekibinde kod okunabilirliği, tutarlılık ve işbirliğini korumak için gereklidir. Sektör uygulamalarını ve belirlenmiş yönergeleri izleyen kodu anlamak, korumak ve genişletmek daha kolaydır. Çoğu proje, kod kuralları aracılığıyla tutarlı bir stil uygular. dotnet/docs
ve dotnet/samples
projeleri özel durum değildir. Bu makale serisinde kodlama kurallarımızı ve bunları zorunlu kılmak için kullandığımız araçları öğreneceksiniz. Kurallarımızı olduğu gibi alabilir veya ekibinizin gereksinimlerine uyacak şekilde değiştirebilirsiniz.
Kurallarımızı aşağıdaki hedeflere göre seçtik:
- Doğruluk: Örneklerimiz kopyalanır ve uygulamalarınıza yapıştırılır. Bunu bekliyoruz, bu nedenle birden çok düzenlemeden sonra bile dayanıklı ve doğru kodlar yapmamız gerekir.
- Öğretim: Örneklerimizin amacı tüm .NET ve C# derslerini vermektir. Bu nedenle, herhangi bir dil özelliğine veya API'ye kısıtlama eklemeyiz. Bunun yerine, bu örnekler bir özelliğin iyi bir seçim olduğunu öğretir.
- Tutarlılık: Okuyucular içeriğimizde tutarlı bir deneyim bekler. Tüm örnekler aynı stile uygun olmalıdır.
- Benimseme: Örneklerimizi yeni dil özelliklerini kullanacak şekilde agresif bir şekilde güncelleştiriyoruz. Bu uygulama, yeni özelliklerin farkındalığını artırarak tüm C# geliştiricilerine daha tanıdık olmalarını sağlar.
Önemli
Bu yönergeler Microsoft tarafından örnekler ve belgeler geliştirmek için kullanılır. .NET Çalışma Zamanı, C# Kodlama Stili ve C# derleyicisi (roslyn) yönergelerinden benimsenmiştir. Açık Kaynak geliştirmesinin üzerinden birkaç yıl geçtikleri için bu yönergeleri seçtik. Topluluk üyelerinin çalışma zamanı ve derleyici projelerine katılmasına yardımcı oldular. Bunlar, yetkili bir liste değil ortak C# kuralları örneği olmalıdır (bunun için bkz . Çerçeve Tasarım Yönergeleri ).
Öğretim ve benimseme hedefleri, docs kodlama kuralının çalışma zamanı ve derleyici kurallarından farklı olmasının nedenidir. Hem çalışma zamanı hem de derleyici, sık erişimli yollar için katı performans ölçümlerine sahiptir. Diğer birçok uygulama bunu yapamaz. Öğretim hedefimiz, herhangi bir yapıyı yasaklamamamızı zorunlu kılınıyor. Bunun yerine örnekler, yapıların ne zaman kullanılması gerektiğini gösterir. Örnekleri çoğu üretim uygulamasından daha agresif bir şekilde güncelleştiriyoruz. Benimseme hedefimiz, geçen yıl yazılmış kodlarda değişiklik gerekmese bile bugün yazmanız gereken kodu göstermemizi zorunlu kılmıştır.
Bu makalede yönergelerimiz açıklanmaktadır. Yönergeler zaman içinde gelişti ve yönergelerimizi izlemeyen örnekler bulacaksınız. Bu örnekleri uyumlu hale getiren PR'leri veya güncelleştirmemiz gereken örneklere dikkatimizi çeken sorunları memnuniyetle karşılıyoruz. Yönergelerimiz Açık Kaynak'tır ve PR'leri ve sorunları memnuniyetle karşılarız. Ancak, gönderiminiz bu önerileri değiştirirse, önce tartışma için bir sorun açın. Yönergelerimizi kullanabilir veya ihtiyaçlarınıza göre uyarlayabilirsiniz.
Araçlar ve çözümleyiciler
Araçlar, ekibinizin kurallarınızı uygulamalarına yardımcı olabilir. Tercih ettiğiniz kuralları zorunlu kılmak için kod analizini etkinleştirebilirsiniz. Visual Studio'nın stil yönergelerinizi otomatik olarak zorlaması için bir editorconfig de oluşturabilirsiniz. Başlangıç noktası olarak, stilimizi kullanmak için dotnet/docs deposunun dosyasını kopyalayabilirsiniz.
Bu araçlar, ekibinizin tercih ettiğiniz yönergeleri benimsemesini kolaylaştırır. Visual Studio, kodunuzu biçimlendirmek için kapsamdaki tüm .editorconfig
dosyalara kuralları uygular. Şirket genelinde kuralları, ekip kurallarını ve hatta ayrıntılı proje kurallarını zorunlu kılmak için birden çok yapılandırma kullanabilirsiniz.
Kod analizi, etkinleştirilen kurallar ihlal edildiğinde uyarılar ve tanılamalar oluşturur. Projenize uygulanmasını istediğiniz kuralları yapılandırabilirsiniz. Ardından her CI derlemesi, kuralların herhangi birini ihlal ettiğinde geliştiricilere bildirir.
Tanılama kimlikleri
Dil yönergeleri
Aşağıdaki bölümlerde, .NET docs ekibinin kod örneklerini ve örneklerini hazırlamak için izlediği uygulamalar açıklanmaktadır. Genel olarak şu uygulamaları izleyin:
- Mümkün olduğunda modern dil özelliklerini ve C# sürümlerini kullanın.
- Eski veya eski dil yapılarından kaçının.
- Yalnızca düzgün işlenebilen özel durumları yakala; genel özel durumları yakalamaktan kaçının.
- Anlamlı hata iletileri sağlamak için belirli özel durum türlerini kullanın.
- Kod okunabilirliğini geliştirmek için koleksiyon düzenlemesi için LINQ sorgularını ve yöntemlerini kullanın.
- Zaman uyumsuz programlamayı zaman uyumsuz olarak kullanın ve G/Ç'ye bağlı işlemler için bekleyin.
- Kilitlenmelere karşı dikkatli olun ve uygun olduğunda kullanın Task.ConfigureAwait .
- Çalışma zamanı türleri yerine veri türleri için dil anahtar sözcüklerini kullanın. Örneğin, yerine System.Stringveya
int
yerine System.Int32kullanınstring
. - İmzasız türler yerine kullanın
int
. kullanımıint
C# genelinde yaygındır ve kullanırkenint
diğer kitaplıklarla etkileşime geçmek daha kolaydır. Özel durumlar, imzalanmamış veri türlerine özgü belgeler içindir. - Yalnızca bir okuyucu ifadeden tür çıkarabildiğinde kullanın
var
. Okuyucular örneklerimizi docs platformunda görüntüler. Değişkenlerin türünü görüntüleyen üzerine gelme veya araç ipuçları yoktur. - Netlik ve basitliği göz önünde bulundurarak kod yazın.
- Aşırı karmaşık ve karmaşık kod mantığını kullanmaktan kaçının.
Daha ayrıntılı yönergelere uyun.
Dize verileri
Aşağıdaki kodda gösterildiği gibi kısa dizeleri birleştirmek için dize ilişkilendirmesini kullanın.
string displayName = $"{nameList[n].LastName}, {nameList[n].FirstName}";
Özellikle büyük miktarda metinle çalışırken dizeleri döngülere eklemek için bir System.Text.StringBuilder nesne kullanın.
var phrase = "lalalalalalalalalalalalalalalalalalalalalalalalalalalalalala"; var manyPhrases = new StringBuilder(); for (var i = 0; i < 10000; i++) { manyPhrases.Append(phrase); } //Console.WriteLine("tra" + manyPhrases);
Diziler
- Bildirim satırında dizileri başlatırken kısa söz dizimini kullanın. Aşağıdaki örnekte yerine kullanamazsınız
var
string[]
.
string[] vowels1 = { "a", "e", "i", "o", "u" };
- Açık örnekleme kullanıyorsanız kullanabilirsiniz
var
.
var vowels2 = new string[] { "a", "e", "i", "o", "u" };
Temsilciler
- Temsilci türleri tanımlamak yerine ve
Action<>
kullanınFunc<>
. Bir sınıfta temsilci yöntemini tanımlayın.
Action<string> actionExample1 = x => Console.WriteLine($"x is: {x}");
Action<string, string> actionExample2 = (x, y) =>
Console.WriteLine($"x is: {x}, y is {y}");
Func<string, int> funcExample1 = x => Convert.ToInt32(x);
Func<int, int, int> funcExample2 = (x, y) => x + y;
- veya
Action<>
temsilcisi tarafından tanımlanan imzayı kullanarak yöntemini çağırınFunc<>
.
actionExample1("string for x");
actionExample2("string for x", "string for y");
Console.WriteLine($"The value is {funcExample1("1")}");
Console.WriteLine($"The sum is {funcExample2(1, 2)}");
Temsilci türünün örneklerini oluşturursanız, kısa söz dizimini kullanın. Sınıfında, temsilci türünü ve eşleşen imzaya sahip bir yöntemi tanımlayın.
public delegate void Del(string message); public static void DelMethod(string str) { Console.WriteLine("DelMethod argument: {0}", str); }
Temsilci türünün bir örneğini oluşturun ve çağırın. Aşağıdaki bildirim, sıkıştırılmış söz dizimini gösterir.
Del exampleDel2 = DelMethod; exampleDel2("Hey");
Aşağıdaki bildirimde tam söz dizimi kullanılır.
Del exampleDel1 = new Del(DelMethod); exampleDel1("Hey");
try-catch
özel durum işlemedeki ve using
deyimleri
Çoğu özel durum işleme için try-catch deyimi kullanın.
static double ComputeDistance(double x1, double y1, double x2, double y2) { try { return Math.Sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); } catch (System.ArithmeticException ex) { Console.WriteLine($"Arithmetic overflow or underflow: {ex}"); throw; } }
C# using deyimini kullanarak kodunuzu basitleştirin. Bloktaki
finally
tek kodun yöntemine Dispose yapılan bir çağrı olduğu bir try-finally deyiminiz varsa, bunun yerine deyiminiusing
kullanın.Aşağıdaki örnekte deyimi
try-finally
yalnızca bloğunufinally
çağırırDispose
.Font bodyStyle = new Font("Arial", 10.0f); try { byte charset = bodyStyle.GdiCharSet; } finally { if (bodyStyle != null) { ((IDisposable)bodyStyle).Dispose(); } }
Deyimiyle
using
de aynı şeyi yapabilirsiniz.using (Font arial = new Font("Arial", 10.0f)) { byte charset2 = arial.GdiCharSet; }
Ayraç gerektirmeyen yeni
using
söz dizimini kullanın:using Font normalStyle = new Font("Arial", 10.0f); byte charset3 = normalStyle.GdiCharSet;
&&
ve ||
işleçleri
&
Aşağıdaki örnekte gösterildiği gibi karşılaştırmaları yerine ve||
yerine|
kullanın&&
.Console.Write("Enter a dividend: "); int dividend = Convert.ToInt32(Console.ReadLine()); Console.Write("Enter a divisor: "); int divisor = Convert.ToInt32(Console.ReadLine()); if ((divisor != 0) && (dividend / divisor) is var result) { Console.WriteLine("Quotient: {0}", result); } else { Console.WriteLine("Attempted division by 0 ends up here."); }
Bölen 0 ise, deyimindeki if
ikinci yan tümce bir çalışma zamanı hatasına neden olabilir. Ancak ilk ifade false olduğunda & işleci kısa devre oluşturur. Yani, ikinci ifadeyi değerlendirmez. & işleci her ikisini de değerlendirerek 0 olduğunda divisor
bir çalışma zamanı hatasına neden olur.
new
operatör
Aşağıdaki bildirimlerde gösterildiği gibi nesne örneklemenin kısa biçimlerinden birini kullanın.
var firstExample = new ExampleClass();
ExampleClass instance2 = new();
Yukarıdaki bildirimler aşağıdaki bildirime eşdeğerdir.
ExampleClass secondExample = new ExampleClass();
Aşağıdaki örnekte gösterildiği gibi nesne oluşturmayı basitleştirmek için nesne başlatıcıları kullanın.
var thirdExample = new ExampleClass { Name = "Desktop", ID = 37414, Location = "Redmond", Age = 2.3 };
Aşağıdaki örnek, önceki örnekle aynı özellikleri ayarlar ancak başlatıcıları kullanmaz.
var fourthExample = new ExampleClass(); fourthExample.Name = "Desktop"; fourthExample.ID = 37414; fourthExample.Location = "Redmond"; fourthExample.Age = 2.3;
Olay işleme
- Daha sonra kaldırmanız gerekmeyen bir olay işleyicisi tanımlamak için lambda ifadesi kullanın:
public Form2()
{
this.Click += (s, e) =>
{
MessageBox.Show(
((MouseEventArgs)e).Location.ToString());
};
}
Lambda ifadesi aşağıdaki geleneksel tanımı kısaltır.
public Form1()
{
this.Click += new EventHandler(Form1_Click);
}
void Form1_Click(object? sender, EventArgs e)
{
MessageBox.Show(((MouseEventArgs)e).Location.ToString());
}
Statik üyeler
Sınıf adını kullanarak statik üyeleri çağırın: ClassName.StaticMember. Bu uygulama, statik erişimi net hale getirerek kodu daha okunabilir hale getirir. Temel sınıfta tanımlanan statik bir üyeyi türetilmiş bir sınıfın adıyla nitelemeyin. Bu kod derlenmiş olsa da kod okunabilirliği yanıltıcıdır ve türetilmiş sınıfa aynı ada sahip statik bir üye eklerseniz kod gelecekte bozulabilir.
LINQ sorguları
Sorgu değişkenleri için anlamlı adlar kullanın. Aşağıdaki örnekte Seattle'da bulunan müşteriler için kullanılır
seattleCustomers
.var seattleCustomers = from customer in customers where customer.City == "Seattle" select customer.Name;
Pascal büyük/küçük harf kullanarak anonim türlerin özellik adlarının doğru şekilde büyük harfe yazıldığından emin olmak için diğer adları kullanın.
var localDistributors = from customer in customers join distributor in distributors on customer.City equals distributor.City select new { Customer = customer, Distributor = distributor };
Sonuçtaki özellik adları belirsiz olduğunda özellikleri yeniden adlandırın. Örneğin, sorgunuz bir müşteri adı ve dağıtımcı kimliği döndürürse, bunları olarak
Name
veID
sonuçta bırakmak yerine, bir müşterinin adı veID
dağıtımcının kimliği olduğunuName
netleştirmek için yeniden adlandırın.var localDistributors2 = from customer in customers join distributor in distributors on customer.City equals distributor.City select new { CustomerName = customer.Name, DistributorID = distributor.ID };
Sorgu değişkenlerinin ve aralık değişkenlerinin bildiriminde örtük yazma kullanın. LINQ sorgularında örtük yazmayla ilgili bu kılavuz, örtük olarak yazılan yerel değişkenler için genel kuralları geçersiz kılar. LINQ sorguları genellikle anonim türler oluşturan projeksiyonları kullanır. Diğer sorgu ifadeleri iç içe genel türlerle sonuç oluşturur. Örtük türemiş değişkenler genellikle daha okunabilir.
var seattleCustomers = from customer in customers where customer.City == "Seattle" select customer.Name;
Önceki örneklerde gösterildiği gibi sorgu yan tümcelerini yan tümcesinin altına
from
hizalayın.Daha sonraki sorgu yan tümcelerinin azaltılmış, filtrelenmiş veri kümesinde çalıştığından emin olmak için diğer sorgu yan tümcelerinden önceki yan tümceleri kullanın
where
.var seattleCustomers2 = from customer in customers where customer.City == "Seattle" orderby customer.Name select customer;
İç koleksiyonlara erişmek için yan
join
tümce yerine birden çokfrom
yan tümce kullanın. Örneğin, bir nesne koleksiyonuStudent
her biri bir test puanı koleksiyonu içerebilir. Aşağıdaki sorgu yürütüldüğünde, 90'ın üzerindeki her puanı ve puanı alan öğrencinin soyadını döndürür.var scoreQuery = from student in students from score in student.Scores! where score > 90 select new { Last = student.LastName, score };
Örtülü olarak belirtilmiş yerel değişkenler
Değişkenin türü atamanın sağ tarafından açıkça belli olduğunda yerel değişkenler için örtük yazma kullanın.
var message = "This is clearly a string."; var currentTemperature = 27;
Tür atamanın sağ tarafından görünmüyorsa var kullanmayın. Türün yöntem adından temiz olduğunu varsaymayın. Değişken türü bir
new
işleç, açık bir atama veya değişmez değere atama ise net olarak kabul edilir.int numberOfIterations = Convert.ToInt32(Console.ReadLine()); int currentMaximum = ExampleClass.ResultSoFar();
Değişkenin türünü belirtmek için değişken adlarını kullanmayın. Doğru olmayabilir. Bunun yerine türünü kullanarak türü belirtin ve değişkenin anlam bilgilerini belirtmek için değişken adını kullanın. Aşağıdaki örnek türü için ve konsoldan okunan bilgilerin anlamını belirtmek üzere bir
iterations
şey kullanmalıdırstring
.var inputInt = Console.ReadLine(); Console.WriteLine(inputInt);
Dinamik yerine kullanmaktan
var
kaçının. Çalışma zamanı türü çıkarımı istediğinizde kullanındynamic
. Daha fazla bilgi için bkz . Tür dinamik kullanma (C# Programlama Kılavuzu).Döngüdeki
for
döngü değişkeni için örtük yazma kullanın.Aşağıdaki örnek, bir
for
deyimde örtük yazma kullanır.var phrase = "lalalalalalalalalalalalalalalalalalalalalalalalalalalalalala"; var manyPhrases = new StringBuilder(); for (var i = 0; i < 10000; i++) { manyPhrases.Append(phrase); } //Console.WriteLine("tra" + manyPhrases);
Döngüdeki
foreach
döngü değişkeninin türünü belirlemek için örtük yazma kullanmayın. Çoğu durumda koleksiyondaki öğelerin türü hemen belli olmaz. Koleksiyon adı yalnızca öğelerinin türünü çıkarması için güvenilir olmamalıdır.Aşağıdaki örnek bir
foreach
deyimde açık yazma kullanır.foreach (char ch in laugh) { if (ch == 'h') Console.Write("H"); else Console.Write(ch); } Console.WriteLine();
LINQ sorgularındaki sonuç dizileri için örtük tür kullanın. LINQ bölümündeki bölümde birçok LINQ sorgusunun örtük türlerin kullanılması gereken anonim türlerle sonuçlandığı açıklanmaktadır. Diğer sorgular, daha okunabilir olan
var
iç içe genel türlere neden olur.Not
Yinelenebilir koleksiyonun bir öğesi türünü yanlışlıkla değiştirmemeye dikkat edin. Örneğin, sorgunun yürütülmesini değiştiren deyiminden
foreach
deyimine geçmek System.Linq.IQueryableSystem.Collections.IEnumerable kolaydır.
Örneklerimizden bazıları bir ifadenin doğal türünü açıklar. Bu örneklerin derleyicinin doğal türü seçmesi için kullanması var
gerekir. Bu örnekler daha az belirgin olsa da, örneğin kullanımı var
gereklidir. Metin davranışı açıklamalıdır.
using yönergelerini ad alanı bildiriminin dışına yerleştirin
Bir using
yönerge bir ad alanı bildiriminin dışında olduğunda, içeri aktarılan ad alanı tam adıdır. Tam ad daha nettir. yönergesi using
ad alanının içinde olduğunda, bu ad alanına göre veya tam adı olabilir.
using Azure;
namespace CoolStuff.AwesomeFeature
{
public class Awesome
{
public void Stuff()
{
WaitUntil wait = WaitUntil.Completed;
// ...
}
}
}
Sınıfına bir başvuru (doğrudan veya dolaylı) WaitUntil olduğunu varsayarsak.
Şimdi biraz değiştirelim:
namespace CoolStuff.AwesomeFeature
{
using Azure;
public class Awesome
{
public void Stuff()
{
WaitUntil wait = WaitUntil.Completed;
// ...
}
}
}
Ve bugün derlenmiş. Ve yarın. Ancak sonraki hafta içinde önceki (dokunulmamış) kod iki hatayla başarısız oluyor:
- error CS0246: The type or namespace name 'WaitUntil' could not be found (are you missing a using directive or an assembly reference?)
- error CS0103: The name 'WaitUntil' does not exist in the current context
Bağımlılıklardan biri bu sınıfı bir ad alanına getirmiştir ve ile sona erer .Azure
:
namespace CoolStuff.Azure
{
public class SecretsManagement
{
public string FetchFromKeyVault(string vaultId, string secretId) { return null; }
}
}
Ad using
alanına yerleştirilen yönerge bağlama duyarlıdır ve ad çözümlemesini karmaşıklaştırır. Bu örnekte, bulduğu ilk ad alanıdır.
CoolStuff.AwesomeFeature.Azure
CoolStuff.Azure
Azure
Genel ad alanı öncesinde Azure
eşleşen CoolStuff.Azure
veya CoolStuff.AwesomeFeature.Azure
eşleşebilecek yeni bir ad alanı ekleme. Bildirimine global::
değiştirici using
ekleyerek sorunu çözebilirsiniz. Ancak, bunun yerine bildirimleri ad alanının dışına yerleştirmek using
daha kolaydır.
namespace CoolStuff.AwesomeFeature
{
using global::Azure;
public class Awesome
{
public void Stuff()
{
WaitUntil wait = WaitUntil.Completed;
// ...
}
}
}
Stil yönergeleri
Genel olarak, kod örnekleri için aşağıdaki biçimi kullanın:
- Girintileme için dört boşluk kullanın. Sekmeleri kullanmayın.
- Okunabilirliği geliştirmek için kodu tutarlı bir şekilde hizalayın.
- Belgelerde, özellikle mobil ekranlarda kod okunabilirliğini geliştirmek için satırları 65 karakterle sınırlayın.
- Netliği artırmak için uzun deyimleri birden çok satıra bölün.
- Ayraçlar için "Allman" stilini kullanın: kendi yeni satırını açın ve kapatın. Ayraçlar geçerli girinti düzeyiyle hizalı.
- Gerekirse satır sonları ikili işleçler öncesinde gerçekleşmelidir.
Açıklama stili
Kısa açıklamalar için tek satırlı açıklamaları (
//
) kullanın.Daha uzun açıklamalar için çok satırlı açıklamalardan (
/* */
) kaçının. Açıklamalar yerelleştirilmemiştir. Bunun yerine, yardımcı makalede daha uzun açıklamalar bulunur.Yöntemleri, sınıfları, alanları ve tüm genel üyeleri tanımlamak için XML açıklamalarını kullanın.
Açıklamayı kod satırının sonuna değil, ayrı bir satıra yerleştirin.
Açıklama metnine büyük harfle başlayın.
Açıklama metnini noktayla sonlandırma.
Aşağıdaki örnekte gösterildiği gibi, açıklama sınırlayıcısı (
//
) ile açıklama metni arasına bir boşluk ekleyin.// The following declaration creates a query. It does not run // the query.
Düzen kuralları
İyi düzen, kodunuzun yapısını vurgulama ve kodun daha kolay okunmasını sağlamak için biçimlendirme kullanır. Microsoft örnekleri ve örnekleri aşağıdaki kurallara uygundur:
Varsayılan Kod Düzenleyicisi ayarlarını kullanın (akıllı girintileme, dört karakterli girintiler, boşluk olarak kaydedilen sekmeler). Daha fazla bilgi için bkz . Seçenekler, Metin Düzenleyicisi, C#, Biçimlendirme.
Satır başına yalnızca bir deyim yazın.
Satır başına yalnızca bir bildirim yazın.
Devamlılık satırları otomatik olarak girintili değilse, bunları bir sekme durağı (dört boşluk) girintileyin.
Yöntem tanımları ve özellik tanımları arasına en az bir boş satır ekleyin.
Aşağıdaki kodda gösterildiği gibi ifadedeki yan tümceleri görünür hale getirmek için parantez kullanın.
if ((startX > endX) && (startX > previousX)) { // Take appropriate action. }
Özel durumlar, örneğin işleç veya ifade önceliğini açıklamasıdır.
Güvenlik
Güvenli Kodlama Yönergeleri'ndeki yönergeleri izleyin.
Geri Bildirim
https://aka.ms/ContentUserFeedback.
Çok yakında: 2024 boyunca, içerik için geri bildirim mekanizması olarak GitHub Sorunları’nı kullanımdan kaldıracak ve yeni bir geri bildirim sistemiyle değiştireceğiz. Daha fazla bilgi için bkz.Gönderin ve geri bildirimi görüntüleyin