3. C# dilinin temelleri
3.1. Introduction
C#'ı öncelikle klasik bir programlama dili olarak ele alacağız. Sınıfları daha sonra ele alacağız. Bir programda iki şey bulunur:
- veriler
- bu verileri işleyen komutlar
Genellikle verileri komutlardan ayırmaya çalışırız:
![]() |
3.2. C#'daki veriler
C# şu veri türlerini kullanır:
- tamsayılar
- gerçek sayılar
- ondalık sayılar
- karakterler ve karakter dizileri
- boole değerleri
- nesneler
3.2.1. Önceden tanımlanmış veri türleri
C# türü | .NET türü | Temsil edilen veri | Sonek değerler | Kodlama | Değer aralığı |
Char (S) | karakter | 2 bayt | Unicode karakter (UTF-16) | ||
Dize (C) | karakter dizisi | Unicode karakter dizisine referans | |||
Int32 (S) | tamsayı | 4 bayt | [-231, 231-1] [–2147483648, 2147483647] | ||
UInt32 (S) | .. | U | 4 bayt | [0, 232-1] [0, 4294967295] | |
Int64 (S) | .. | L | 8 bayt | [-263, 263 -1] [–9223372036854775808, 9223372036854775807] | |
UInt64 (S) | .. | UL | 8 bayt | [0, 264 -1] [0, 18446744073709551615] | |
.. | 1 bayt | [-27 , 27 -1] [-128,+127] | |||
Bayt (S) | .. | 1 bayt | [0 , 28 -1] [0,255] | ||
Int16 (S) | .. | 2 bayt | [-215, 215-1] [-32768, 32767] | ||
UInt16 (S) | .. | 2 bayt | [0, 216-1] [0,65535] | ||
Tek (S) | gerçek sayı | F | 4 bayt | [1.5 10-45, 3.4 10+38] mutlak değer | |
Çift (S) | .. | D | 8 bayt | [-1.7 10+308, 1.7 10+308] mutlak değer | |
Ondalık (S) | ondalık sayı | M | 16 bayt | [1.0 10-28,7.9 10+28], 28 anlamlı basamaklı mutlak değer | |
Boolean (S) | .. | 1 bayt | true, false | ||
Nesne (C) | nesne referansı | nesne referansı |
Yukarıda, C# türlerinin karşısına, bu türün bir yapı olması durumunda (S) ve bir sınıf olması durumunda (C) yorumuyla birlikte eşdeğer .NET türleri yazılmıştır. 32 bitlik bir tamsayı için iki olası tür olduğu görülmektedir: int ve Int32. int türü bir C# türüdür. Int32, System ad alanına ait bir yapıdır. Dolayısıyla tam adı System.Int32'tir. int türü, .NET System.Int32 yapısını ifade eden bir C# takma adıdır. Aynı şekilde, C# türü string, .NET ve System.String türleri için bir takma addır. System.String bir sınıftır, yapı değildir. Bu iki kavram birbirine yakındır, ancak aralarında şu temel fark vardır:
- Structure türündeki bir değişken, değeri üzerinden işlenir
- Classe türündeki bir değişken ise adresi üzerinden işlenir (nesne yönelimli programlamada referans).
Hem structure hem de classe, özniteliklere ve yöntemlere sahip karmaşık türlerdir. Dolayısıyla şu şekilde yazabiliriz:
Yukarıdaki 3 sabiti varsayılan olarak C# int türündedir, dolayısıyla .NET System.Int32 türündedir. Bu yapı, GetType() adlı bir yönteme sahiptir; bu yöntem, System.Int32 veri türünün özelliklerini kapsayan bir nesne döndürür. Bunlar arasında, FullName özelliği, türün tam adını döndürür. Dolayısıyla, 3 sabitinin ilk bakışta göründüğünden daha karmaşık bir nesne olduğu anlaşılmaktadır.
İşte bu farklı noktaları gösteren bir program:
using System;
namespace Chap1 {
class P00 {
static void Main(string[] args) {
// örnek 1
int ent = 2;
float fl = 10.5F;
double d = -4.6;
string s = "essai";
uint ui = 5;
long l = 1000;
ulong ul = 1001;
byte octet = 5;
short sh = -4;
ushort ush = 10;
decimal dec = 10.67M;
bool b = true;
Console.WriteLine("Type de ent[{1}] : [{0},{2}]", ent.GetType().FullName, ent,sizeof(int));
Console.WriteLine("Type de fl[{1}]: [{0},{2}]", fl.GetType().FullName, fl, sizeof(float));
Console.WriteLine("Type de d[{1}] : [{0},{2}]", d.GetType().FullName, d, sizeof(double));
Console.WriteLine("Type de s[{1}] : [{0}]", s.GetType().FullName, s);
Console.WriteLine("Type de ui[{1}] : [{0},{2}]", ui.GetType().FullName, ui, sizeof(uint));
Console.WriteLine("Type de l[{1}] : [{0},{2}]", l.GetType().FullName, l, sizeof(long));
Console.WriteLine("Type de ul[{1}] : [{0},{2}]", ul.GetType().FullName, ul, sizeof(ulong));
Console.WriteLine("Type de b[{1}] : [{0},{2}]", octet.GetType().FullName, octet, sizeof(byte));
Console.WriteLine("Type de sh[{1}] : [{0},{2}]", sh.GetType().FullName, sh, sizeof(short));
Console.WriteLine("Type de ush[{1}] : [{0},{2}]", ush.GetType().FullName, ush, sizeof(ushort));
Console.WriteLine("Type de dec[{1}] : [{0},{2}]", dec.GetType().FullName, dec, sizeof(decimal));
Console.WriteLine("Type de b[{1}] : [{0},{2}]", b.GetType().FullName, b, sizeof(bool));
}
}
}
- 7. satır: ent tamsayısının tanımlanması
- 19. satır: v değişkeninin türü v.GetType().FullName ile elde edilebilir. S yapısının boyutu sizeof(S) ile elde edilebilir. Console.WriteLine("... {0} ... {1} ...", param0, param1, ...) komutu, ilk parametresi olan metni ekrana yazar; bu sırada her bir {i} ifadesini parami ifadesinin değeriyle değiştirir.
- 22. satır: string türü bir sınıfı belirtir, bir yapıyı değil; bu nedenle sizeof operatörü kullanılamaz.
İşte yürütme sonucu:
Ekranda C# takma adları yerine .NET türleri görüntülenir.
3.2.2. Sabit verilerin gösterimi
145, -7, 0xFF (onaltılık) | |
100000L | |
134,789, -45E-18 (-45 × 10⁻¹⁸) | |
134.789F, -45E-18F (-45 10-18) | |
100000M | |
'A', 'b' | |
"bugün" "c:\\chap1\\paragraph3" @"c:\chap1\paragraph3" | |
true, false | |
new DateTime(1954,10,13) (yıl, ay, gün) 13/10/1954 için |
İki sabit dizeye dikkat edelim: "c:\\chap1\\paragraph3" ve @"c:\chap1\paragraph3". Sabit dizelerde, \ karakteri yorumlanır. Dolayısıyla "\n", \ ve n karakterlerinin ardışık dizisini değil, satır sonu işaretini temsil eder. Bu karakter dizisini elde etmek istersek, "\\n" yazmamız gerekir; burada \\ dizisi tek bir \ karakteri olarak yorumlanır. Aynı sonucu elde etmek için @"\n" de yazılabilir. @"metin" sözdizimi, metnin tam olarak yazıldığı gibi alınmasını gerektirir. Buna bazen "verbatim" dize denir.
3.2.3. Veri Bildirimi
3.2.3.1. Bildirimlerin rolü
Bir program, bir ad ve bir tür ile tanımlanan verileri işler. Bu veriler bellekte depolanır. Programın derlenmesi sırasında, derleyici her veriye bir adres ve bir boyut ile tanımlanan bir bellek konumu atar. Bunu, programcı tarafından yapılan tanımlamalardan yararlanarak yapar.
Ayrıca bu bildirimler, derleyicinin programlama hatalarını tespit etmesini sağlar. Dolayısıyla şu işlem
x=x*2;
ifadesi, örneğin x bir karakter dizisiyse hatalı olarak bildirilir.
3.2.3.2. Sabitlerin Bildirilmesi
Bir sabitin bildirim sözdizimi şöyledir:
Örneğin:
Neden sabitler tanımlanır?
- Sabitlere anlamlı isimler verilirse programın okunması daha kolay olur:
- "Sabit" değer değişirse, programı değiştirmek daha kolay olacaktır. Dolayısıyla önceki örnekte, KDV oranı %33'e çıkarsa, yapılması gereken tek değişiklik, değerini tanımlayan komutu değiştirmek olacaktır:
Programda 0,186 değerini açıkça kullanmış olsaydık, o zaman değiştirilmesi gereken çok sayıda komut olurdu.
3.2.3.3. Değişkenlerin tanımlanması
Bir değişken, bir adla tanımlanır ve bir veri türüne aittir. C#, büyük ve küçük harfleri ayırt eder. Dolayısıyla, FIN ve fin değişkenleri farklıdır.
Değişkenler, tanımlandıkları sırada başlatılabilir. Bir veya daha fazla değişkeni tanımlamanın sözdizimi şöyledir:
burada Identificateur_de_type, önceden tanımlanmış bir tür veya programcı tarafından tanımlanmış bir türdür. İsteğe bağlı olarak, bir değişken tanımlandığı sırada başlatılabilir.
Ayrıca, Identificateur_de_type yerine var anahtar sözcüğünü kullanarak bir değişkenin tam türünü belirtmeme seçeneği de vardır:
var anahtar sözcüğü, değişkenlerin belirli bir türüne sahip olmadığı anlamına gelmez. variablei değişkeni, kendisine atanan valeuri veri türüne sahiptir. Derleyicinin değişkenin türünü çıkarabilmesi için burada başlatma zorunludur.
İşte bir örnek:
using System;
namespace Chap1 {
class P00 {
static void Main(string[] args) {
int i=2;
Console.WriteLine("Type de int i=2 : {0},{1}",i.GetType().Name,i.GetType().FullName);
var j = 3;
Console.WriteLine("Type de var j=3 : {0},{1}", j.GetType().Name, j.GetType().FullName);
var aujourdhui = DateTime.Now;
Console.WriteLine("Type de var aujourdhui : {0},{1}", aujourdhui.GetType().Name, aujourdhui.GetType().FullName);
}
}
}
- 6. satır: açıkça türlendirilmiş bir veri
- 7. satır: (veri).GetType().Name, (veri)'nin kısa adıdır; (veri).GetType().FullName ise (veri)'nin tam adıdır
- 8. satır: örtük olarak türlendirilmiş bir veri. 3, int türünde olduğu için, j de int türünde olacaktır.
- 10. satır: örtük olarak türlendirilmiş bir veri. DateTime.Now, DateTime türünde olduğu için, aujourdhui, DateTime türünde olacaktır.
Çalıştırıldığında şu sonuç elde edilir:
var anahtar sözcüğüyle örtük olarak türlendirilmiş bir değişkenin türü daha sonra değiştirilemez. Dolayısıyla, kodun 10. satırından sonra şu satırı yazamayız:
var aujourdhui = "aujourd'hui";
Daha sonra göreceğiz ki, bir ifadede bir türü “anında” tanımlamak mümkündür. Bu durumda söz konusu tür, kullanıcının bir ad vermediği anonim bir türdür. Bu yeni türe bir ad verecek olan derleyicidir. Anonim türdeki bir verinin bir değişkene atanması gerekiyorsa, bu değişkeni tanımlamanın tek yolu var anahtar sözcüğünü kullanmaktır.
3.2.4. Sayılar ve karakter dizeleri arasındaki dönüştürmeler
nombre.ToString() | |
int.Parse(dize) veya System.Int32.Parse | |
long.Parse(dize) veya System.Int64.Parse | |
double.Parse (dizi) veya System.Double.Parse (dizi) | |
float.Parse (dize) veya System.Float.Parse (dize) |
Dize geçerli bir sayı değilse, dizenin sayıya dönüştürülmesi başarısız olabilir. Bu durumda, istisna adı verilen ölümcül bir hata oluşur. Bu hata, aşağıdaki try/catch cümlesiyle yönetilebilir:
try{
appel de la fonction susceptible de générer l'exception
} catch (Exception e){
traiter l'exception e
}
instruction suivante
İşlev bir istisna oluşturmazsa, bir sonraki komuta geçilir; aksi takdirde catch cümlesinin gövdesine geçilir ve ardından bir sonraki komuta geçilir. İstisna yönetimine daha sonra tekrar değineceğiz. İşte sayılar ve karakter dizeleri arasında dönüştürme tekniklerini gösteren bir program. Bu örnekte affiche işlevi, parametresinin değerini ekrana yazdırır. Dolayısıyla affiche(S), S'nin değerini ekrana yazdırır; burada S, string türündedir.
using System;
namespace Chap1 {
class P01 {
static void Main(string[] args) {
// veriler
const int i = 10;
const long l = 100000;
const float f = 45.78F;
double d = -14.98;
// sayı --> dize
affiche(i.ToString());
affiche(l.ToString());
affiche(f.ToString());
affiche(d.ToString());
//boole --> dize
const bool b = false;
affiche(b.ToString());
// dize --> int
int i1;
i1 = int.Parse("10");
affiche(i1.ToString());
try {
i1 = int.Parse("10.67");
affiche(i1.ToString());
} catch (Exception e) {
affiche("Erreur : " + e.Message);
}
// dize --> long
long l1;
l1 = long.Parse("100");
affiche(l1.ToString());
try {
l1 = long.Parse("10.675");
affiche(l1.ToString());
} catch (Exception e) {
affiche("Erreur : " + e.Message);
}
// dize --> double
double d1;
d1 = double.Parse("100,87");
affiche(d1.ToString());
try {
d1 = double.Parse("abcd");
affiche(d1.ToString());
} catch (Exception e) {
affiche("Erreur : " + e.Message);
}
// dize --> float
float f1;
f1 = float.Parse("100,87");
affiche(f1.ToString());
try {
d1 = float.Parse("abcd");
affiche(f1.ToString());
} catch (Exception e) {
affiche("Erreur : " + e.Message);
}
}// son main
public static void affiche(string S) {
Console.Out.WriteLine("S={0}",S);
}
}// sınıf sonu
}
30-32. satırlarda, meydana gelebilecek olası istisna işlenir. e.Message, e istisnasıyla ilişkili hata mesajıdır.
Elde edilen sonuçlar şunlardır:
Dize biçimindeki gerçek sayılarda ondalık nokta yerine virgül kullanılması gerektiğine dikkat edilmelidir. Dolayısıyla şu şekilde yazılmalıdır:
ama
3.2.5. Veri tabloları
C#'da bir dizi, aynı türdeki verileri tek bir tanımlayıcı altında bir araya getiren bir nesnedir. Bildirimi şu şekildedir:
n, dizinin içerebileceği veri sayısını belirtir. Tableau[i] sözdizimi, i'nin [0,n-1] aralığına ait olduğu [i] numaralı veriyi belirtir. i'in [0,n-1] aralığına ait olmadığı Tableau[i] verisine yapılan herhangi bir başvuru bir istisna oluşturacaktır. Bir dizi, tanımlandığı anda başlatılabilir:
veya daha basit bir şekilde:
Dizilerin, dizideki eleman sayısını gösteren Length özelliği vardır.
İki boyutlu bir dizi şu şekilde tanımlanabilir:
Type[,] dizi = new Type[n,m];
burada n satır sayısı, m ise sütun sayısıdır. Tableau[i,j] sözdizimi, tablonun i'inci satırındaki j'inci öğeyi belirtir. İki boyutlu tablo da tanımlandığı sırada aynı anda başlatılabilir:
veya daha basit bir şekilde:
Her bir boyuttaki eleman sayısı, GetLength(i) yöntemi ile elde edilebilir; burada i=0, 1. indekse karşılık gelen boyutu, i=1 ise 2. indekse karşılık gelen boyutu temsil eder, …
Toplam boyut sayısı Rank özelliği ile, toplam eleman sayısı ise Length özelliği ile elde edilir.
Bir dizi dizisi şu şekilde tanımlanır:
Type[][] tablo = new Type[n][];
Yukarıdaki tanım, n satırlık bir dizi oluşturur. Her bir tableau[i] elemanı, tek boyutlu bir dizi referansıdır. Bu tableau[i] referansları, yukarıdaki tanım sırasında başlatılmaz. Değerleri null referansıdır.
Aşağıdaki örnek, bir dizi dizisinin oluşturulmasını göstermektedir:
// dizilerin dizisi
string[][] noms = new string[3][];
for (int i = 0; i < noms.Length; i++) {
noms[i] = new string[i + 1];
}//for
// başlatma
for (int i = 0; i < noms.Length; i++) {
for (int j = 0; j < noms[i].Length; j++) {
noms[i][j] = "nom" + i + j;
}//for j
}//for i
- 2. satır: noms adlı, string[][] türünde 3 elemanlı bir dizi. Her eleman, elemanları string[] türünde olan bir dizi işaretçisidir (bir nesne referansı).
- 3-5. satırlar: noms dizisinin 3 elemanı başlatılır. Her biri artık string[] türündeki elemanlardan oluşan bir diziye "işaret eder". noms[i][j], noms[i] tarafından referans verilen string [] türündeki dizinin j elemanıdır.
- 9. satır: çift döngü içinde noms[i][j] elemanının başlatılması. Burada noms[i], i+1 elemanlı bir dizidir. noms[i] bir dizi olduğu için, noms[i].Length, eleman sayısını gösterir.
İşte az önce tanıttığımız üç dizi türünü bir araya getiren bir örnek:
using System;
namespace Chap1 {
// diziler
using System;
// test sınıfı
public class P02 {
public static void Main() {
// başlatılmış 1 boyutlu bir dizi
int[] entiers = new int[] { 0, 10, 20, 30 };
for (int i = 0; i < entiers.Length; i++) {
Console.Out.WriteLine("entiers[{0}]={1}", i, entiers[i]);
}//for
// başlatılmış 2 boyutlu bir dizi
double[,] réels = new double[,] { { 0.5, 1.7 }, { 8.4, -6 } };
for (int i = 0; i < réels.GetLength(0); i++) {
for (int j = 0; j < réels.GetLength(1); j++) {
Console.Out.WriteLine("réels[{0},{1}]={2}", i, j, réels[i, j]);
}//for j
}//for i
// bir dizi dizisi
string[][] noms = new string[3][];
for (int i = 0; i < noms.Length; i++) {
noms[i] = new string[i + 1];
}//için
// başlatma
for (int i = 0; i < noms.Length; i++) {
for (int j = 0; j < noms[i].Length; j++) {
noms[i][j] = "nom" + i + j;
}//for j
}//for i
// görüntüleme
for (int i = 0; i < noms.Length; i++) {
for (int j = 0; j < noms[i].Length; j++) {
Console.Out.WriteLine("noms[{0}][{1}]={2}", i, j, noms[i][j]);
}//j için
}//i için
}//Ana Sayfa
}//sınıf
}//ad alanı
Çalıştırıldığında şu sonuçları elde ederiz:
3.3. C#'ın temel komutları
Aşağıdakiler ayırt edilir:
1 bilgisayar tarafından yürütülen temel komutlar.
2 programın akışını kontrol eden komutlar.
Bir mikrobilgisayarın ve çevre birimlerinin yapısı incelendiğinde temel komutlar açıkça görülür.
![]() |
-
klavyeden gelen bilgilerin okunması
-
bilgilerin işlenmesi
-
Bilgilerin ekrana yazılması
3.3.1. Ekrana yazma
Ekrana yazma için çeşitli komutlar vardır:
Console.Out.WriteLine(expression)
Console.WriteLine(expression)
Console.Error.WriteLine (expression)
burada expression, ekranda görüntülenmek üzere karakter dizisine dönüştürülebilen herhangi bir veri türüdür. Tüm C# nesneleri veya .NET nesneleri, bu dönüşümü gerçekleştirmek için kullanılan ToString() yöntemine sahiptir.
System.Console sınıfı, ekrana yazma işlemlerine (Write, WriteLine) erişim sağlar. Console sınıfı, TextWriter türünde yazma akışları olan Out ve Error adlı iki özelliğe sahiptir:
- Console.WriteLine() işlevi, Console.Out.WriteLine() işlevine eşdeğerdir ve genellikle ekrana atanan Out akışına yazma işlemi gerçekleştirir.
- Console.Error.WriteLine(), genellikle ekrana da bağlı olan Error akışına yazdırır.
Out ve Error akışları, birazdan göreceğimiz gibi, programın çalışması sırasında metin dosyalarına yönlendirilebilir.
3.3.2. Klavyeyle girilen verilerin okunması
Klavye kaynaklı veri akışı, TextReader türündeki Console.In nesnesi ile temsil edilir. Bu tür nesneler, ReadLine yöntemi kullanılarak bir metin satırını okumaya olanak tanır:
Console sınıfı, varsayılan olarak In akışına eşleştirilmiş ReadLine yöntemini sunar. Dolayısıyla şu şekilde yazılabilir:
Klavyeyle girilen satır, ligne değişkenine kaydedilir ve daha sonra program tarafından kullanılabilir. In akışı, Out ve Error akışları gibi bir dosyaya yönlendirilebilir.
3.3.3. Giriş-Çıkış Örneği
Aşağıda, klavye/ekran giriş-çıkış işlemlerini gösteren kısa bir program yer almaktadır:
using System;
namespace Chap1 {
// test sınıfı
public class P03 {
public static void Main() {
// Out akışına yazma
object obj = new object();
Console.Out.WriteLine(obj);
// Hata akışına yazma
int i = 10;
Console.Error.WriteLine("i=" + i);
// klavyeden girilen bir satırı okuma
Console.Write("Tapez une ligne : ");
string ligne = Console.ReadLine();
Console.WriteLine("ligne={0}", ligne);
}//main sonu
}//sınıf sonu
}
- 9. satır: obj bir nesne referansıdır
- 10. satır: obj ekrana yazılır. Varsayılan olarak, obj.ToString() yöntemi çağrılır.
- 14. satır: Şu şekilde de yazılabilir:
Console.Error.WriteLine("i={0}",i);
İlk parametre "i={0}" görüntüleme biçimidir, diğer parametreler ise görüntülenecek ifadeleridir. {n} öğeleri "konumsal" parametrelerdir. Yürütme sırasında {n} parametresi, n numaralı ifadenin değeriyle değiştirilir.
Çalıştırma sonucu şöyledir:
- 1. satır: kodun 10. satırının ürettiği çıktı. obj.ToString() yöntemi, obj değişkeninin tür adını görüntüledi: System.Object. object türü, .NET System.Object türünün bir C# takma adıdır.
3.3.4. G/Ç Yönlendirme
DOS ve UNIX altında şu üç standart aygıt bulunur:
- standart giriş aygıtı - varsayılan olarak klavyeyi ifade eder ve 0 numaralıdır
- standart çıkış aygıtı - varsayılan olarak ekranı belirtir ve 1 numaralıdır
- standart hata aygıtı - varsayılan olarak ekranı belirtir ve 2 numaralıdır
C#'da, Console.Out yazma akışı 1 numaralı aygıta yazar, Console.Error yazma akışı 2 numaralı aygıta yazar ve Console.In okuma akışı 0 numaralı aygıttan gelen verileri okur.
DOS veya Unix altında bir program çalıştırıldığında, yürütülen program için 0, 1 ve 2 numaralı aygıtların hangileri olacağı belirlenebilir. Şu komut satırını ele alalım:
pg programının argi argümanlarının arkasında, standart G/Ç aygıtlarını dosyalara yeniden yönlendirebiliriz:
0 numaralı standart giriş akışı, in.txt dosyasına yönlendirilir. Dolayısıyla programda Console.In akışı, verilerini in.txt dosyasından alacaktır. | |
1 numaralı çıkışı out.txt dosyasına yönlendirir. Bu, programda Console.Out akışının verilerini out.txt dosyasına yazacağı anlamına gelir | |
aynı şekilde, ancak yazılan veriler out.txt dosyasının mevcut içeriğine eklenir. | |
2 numaralı çıkışı error.txt dosyasına yönlendirir. Bu, programda Console.Error akışının verilerini error.txt dosyasına yazmasına neden olur | |
Aynı şekilde, ancak yazılan veriler error.txt dosyasının mevcut içeriğine eklenir. | |
1 ve 2 numaralı aygıtların her ikisi de dosyalara yönlendirilir |
pg programının G/Ç akışlarını dosyalara yönlendirmek için pg programının değiştirilmesine gerek olmadığına dikkat edilmelidir. 0, 1 ve 2 numaralı aygıtların niteliğini belirleyen işletim sistemidir. Şu programı ele alalım:
using System;
namespace Chap1 {
// yönlendirmeler
public class P04 {
public static void Main(string[] args) {
// In akışını okuma
string data = Console.In.ReadLine();
// Out akışına yazma
Console.Out.WriteLine("écriture dans flux Out : " + data);
// Hata akışına yazma
Console.Error.WriteLine("écriture dans flux Error : " + data);
}//Ana
}//sınıf
}
Bu kaynak koddan yürütülebilir dosyayı oluşturalım:
![]() |
- [1] olarak: yürütülebilir dosya, projeye sağ tıklayıp / Build
- [2]: Bir DOS penceresinde, 04.exe yürütülebilir dosyası, projenin bin/Release klasöründe oluşturulmuştur.
[2] DOS penceresinde şu komutları girelim:
- 1. satır: test dizesini in.txt dosyasına ekliyoruz
- 2-3. satırlar: Doğrulama amacıyla in.txt dosyasının içeriğini görüntüleyelim
- 4. satır: 04.exe programı çalıştırılır. In akışı, in.txt dosyasına yönlendirilir; Out akışı out.txt dosyasına, Error akışı ise err.txt dosyasına yönlendirilir. Çalıştırma işlemi herhangi bir çıktı göstermez.
- 5-6. satırlar: out.txt dosyasının içeriği. Bu içerik bize şunu göstermektedir:
- in.txt dosyası okundu
- ekran çıktısı out.txt dosyasına yönlendirilmiştir
- 7-8. satırlar: err.txt dosyası için benzer doğrulama
Out ve In akışlarının aynı aygıtlara yazmadıkları açıkça görülmektedir, çünkü bu akışlar ayrı ayrı yönlendirilebilmiştir.
3.3.5. Bir ifadenin değerinin bir değişkene atanması
Burada variable=expression; işlemiyle ilgileniyoruz
İfade şu türlerden olabilir: aritmetik, ilişkisel, boole, karakter
3.3.5.1. Atama işleminin yorumlanması
variable=expression; işlemi
işlemi, kendisi de bir ifadedir ve değerlendirilmesi şu şekilde gerçekleşir:
- atama işleminin sağ tarafı değerlendirilir: sonuç bir V değeridir.
- V değeri değişkene atanır
- V değeri, bu kez bir ifade olarak ele alındığında atama işleminin sonucudur.
İşte bu şekilde
işlemi geçerlidir. Öncelik kuralı gereği, en sağdaki = operatörü değerlendirilecektir. Dolayısıyla
V2=ifade ifadesi değerlendirilir ve değeri V olur. Bu ifadenin değerlendirilmesi, V'ye V2 değerinin atanmasına neden olur. Ardından bir sonraki = operatörü şu şekilde değerlendirilir:
Bu ifadenin değeri yine V'dir. Değerlendirilmesi sonucunda V, V1'e atanır.
Dolayısıyla, V1=V2=ifade
değerlendirilmesi sonucunda
- expression değişkeninin değerinin V1 ve V2 değişkenlerine atanmasına neden olur
- expression değerini sonuç olarak verir.
Bunu şu tür bir ifadeye genelleştirebiliriz:
3.3.5.2. Aritmetik ifade
Aritmetik ifadelerde kullanılan işleçler şunlardır:
-
toplama
-
çıkarma
* çarpma
/ bölme: en az bir terim gerçek sayı ise sonuç tam bölümdür. Her iki terim de tamsayı ise sonuç tam bölümdür. Dolayısıyla 5/2 -> 2 ve 5,0/2 -> 2,5.
% bölme: işlenenlerin türü ne olursa olsun sonuç kalıntıdır; bölme sonucu ise tam sayıdır. Dolayısıyla bu, modül işlemidir.
Çeşitli matematiksel fonksiyonlar mevcuttur. İşte bunlardan birkaçı:
kare kök | |
kosinüs | |
Sinüs | |
Tanjant | |
x'in y'inci kuvveti (x>0) | |
Üstel | |
Neper logaritması | |
mutlak değer |
vb...
Tüm bu fonksiyonlar, Math adlı bir C# sınıfında tanımlanmıştır. Bunları kullanırken, tanımlandıkları sınıfın adını ön ek olarak eklemek gerekir. Dolayısıyla şöyle yazılır:
Math sınıfının tam tanımı şöyledir:





3.3.5.3. Aritmetik ifadelerin değerlendirilmesinde öncelikler
Bir aritmetik ifadenin değerlendirilmesi sırasında işleçlerin önceliği şu şekildedir (en yüksek öncelikli olandan en düşük öncelikli olana doğru):
Aynı bloktaki operatörler [ ] aynı önceliğe sahiptir.
3.3.5.4. İlişkisel ifadeler
İşlemciler şunlardır:
işlemcilerin öncelikleri
Bir ilişkisel ifadenin sonucu, ifade yanlışsa false, aksi takdirde true'tir.
İki karakterin karşılaştırılması
C1 ve C2 olmak üzere iki karakter varsayalım. Bunları aşağıdaki operatörlerle karşılaştırmak mümkündür
Bu durumda, sayılar olan Unicode kodları karşılaştırılır. Unicode sıralamasına göre aşağıdaki ilişkiler geçerlidir:
İki karakter dizisinin karşılaştırılması
Dizgiler karakter karakter karşılaştırılır. İki karakter arasında karşılaşılan ilk eşitsizlik, dizgiler üzerinde de aynı yönde bir eşitsizliğe yol açar.
Örnekler:
"Kedi" ve "Köpek" dizelerini karşılaştıralım
![]() |
Bu son eşitsizlik, "Chat" < "Chien" olduğunu gösterir.
"Chat" ve "Chaton" dizelerini karşılaştıralım. "Chat" dizesi tükenene kadar her zaman eşitlik vardır. Bu durumda, tükenen dize "daha küçük" olarak ilan edilir. Dolayısıyla şu ilişki ortaya çıkar:
İki dizenin karşılaştırma işlevleri
İki dizenin eşit olup olmadığını kontrol etmek için == ve != karşılaştırma operatörleri veya System.String sınıfının Equals yöntemi kullanılabilir. <<=, >, >= ilişkileri için ise System.String sınıfındaki CompareTo yöntemini kullanmak gerekir:
using System;
namespace Chap1 {
class P05 {
static void Main(string[] args) {
string chaine1="chat", chaine2="chien";
int n = chaine1.CompareTo(chaine2);
bool egal = chaine1.Equals(chaine2);
Console.WriteLine("i={0}, egal={1}", n, egal);
Console.WriteLine("chien==chaine1:{0},chien!=chaine2:{1}", "chien"==chaine1,"chien" != chaine2);
}
}
}
- satırda, i değişkeninin değeri şöyledir:
0 iki dize eşitse
1 1 numaralı dize > 2 numaralı dize ise
-1 1 numaralı dize 2 numaralı dizeden küçükse
- satırda, egal değişkeni, iki dize eşitse true değerini, aksi takdirde false değerini alır. 10. satırda, iki dizenin eşit olup olmadığını kontrol etmek için == ve != operatörleri kullanılır.
Çalıştırma sonuçları:
3.3.5.5. Boole ifadeleri
Kullanılabilen operatörler şunlardır: AND (&&) OR (||) NOT (!). Bir boole ifadesinin sonucu bir boole değeridir.
işlemcilerin öncelikleri:
- !
- &&
- ||
double x = 3.5;
bool valide = x > 2 && x < 4;
İlişkisel operatörler, && ve || operatörlerine göre önceliklidir.
3.3.5.6. Bit işlemleri
İşlemciler
i ve j iki tamsayı olsun.
, i'yi n bit sola kaydırır. Gelen bitler sıfırdır. | |
i'yi n bit sağa kaydırır. i işaretli bir tamsayıysa (signed char, int, long), işaret biti korunur. | |
i ve j'nin bit bazında mantıksal OR işlemini gerçekleştirir. | |
i ve j'nin bit bazında mantıksal OR işlemini gerçekleştirir. | |
i'yi 1'e tamamlar | |
i ve j'nin OU EXCLUSIF değerini verir |
Şu kod olsun:
short i = 100, j = -13;
ushort k = 0xF123;
Console.WriteLine("i=0x{0:x4}, j=0x{1:x4}, k=0x{2:x4}", i,j,k);
Console.WriteLine("i<<4=0x{0:x4}, i>>4=0x{1:x4},k>>4=0x{2:x4},i&j=0x{3:x4},i|j=0x{4:x4},~i=0x{5:x4},j<<2=0x{6:x4},j>>2=0x{7:x4}", i << 4, i >> 4, k >> 4, (short)(i & j), (short)(i | j), (short)(~i), (short)(j << 2), (short)(j >> 2));
- {0:x4} biçimi, 0 numaralı parametreyi 4 karakterlik (4) onaltılık (x) biçimde görüntüler.
Çalıştırma sonuçları şöyledir:
3.3.5.7. İşlemcilerin birleşimi
a=a+b, a+=b şeklinde yazılabilir
a=a-b, a-=b şeklinde yazılabilir
Aynı durum /, %, *, <<, >>, &, |, ^ operatörleri için de geçerlidir. Dolayısıyla a=a/2;, a/=2; şeklinde yazılabilir
3.3.5.8. Artırma ve azaltma operatörleri
variable++ notasyonu, variable=variable+1 veya variable+=1 anlamına gelir
variable-- notasyonu, variable=variable-1 veya variable-=1 anlamına gelir.
3.3.5.9. Üçlü operatör nedir?
Şu ifade
şu şekilde hesaplanır:
1 expr_cond ifadesi değerlendirilir. Bu, değeri vrai veya faux olan bir koşullu ifadedir
2 İfade doğruysa, ifadenin değeri expr1 olur ve expr2 değerlendirilmez.
3 Yanlışsa, tam tersi olur: ifadenin değeri expr2 olur ve expr1 değerlendirilmez.
i=(j>4 ? j+1:j-1); işlemi, i değişkenine j+1 değerini atayacaktır; aksi takdirde j>4 veya j-1 değerini atayacaktır. Bu, if(j>4) i=j+1; else i=j-1; yazmakla aynıdır, ancak daha özlüdür.
3.3.5.10. Operatörlerin genel önceliği
gd | |
dg | |
dg | |
gd | |
gd | |
gd | |
gd | |
gd | |
gd | |
gd | |
gd | |
gd | |
gd | |
dg | |
dg |
gd, eşit öncelik durumunda soldan sağa önceliğin geçerli olduğunu belirtir. Bu, bir ifadede aynı önceliğe sahip operatörler olduğunda, ifadedeki en soldaki operatörün ilk olarak değerlendirildiği anlamına gelir. dg, sağdan sola önceliği belirtir.
3.3.5.11. Tür Değişiklikleri
Bir ifadede, bir değerin kodlamasını geçici olarak değiştirmek mümkündür. Buna verinin türünü değiştirmek veya İngilizce'de "type casting" denir. Bir ifadede bir değerin türünü değiştirmenin sözdizimi şöyledir:
Böylece değer, belirtilen türü alır. Bu, değerin kodlamasında bir değişikliğe yol açar.
using System;
namespace Chap1 {
class P06 {
static void Main(string[] args) {
int i = 3, j = 4;
float f1=i/j;
float f2=(float)i/j;
Console.WriteLine("f1={0}, f2={1}",f1,f2);
}
}
}
- 7. satırda, f1 değeri 0,0 olacaktır. 3/4 bölme işlemi, her iki işleneni de int türünde olduğu için tam sayı bölme işlemidir.
- 8. satırda, (float)i, i'nin float'e dönüştürülmüş değeridir. Şimdi, float türünde bir gerçek sayı ile int türünde bir tamsayı arasında bir bölme işlemi söz konusudur. Ardından gerçek sayılar arasında bölme işlemi gerçekleştirilir. j değeri de float türüne dönüştürülecek ve ardından iki gerçek sayı arasında bölme işlemi yapılacaktır. f2 değeri bu durumda 0,75 olacaktır.
İşte yürütme sonuçları:
(float)i işleminde:
- i, 2 baytlık tam kodlanmış bir değerdir
- (float) i ise 4 baytlık gerçek sayı olarak yaklaşık olarak kodlanmış aynı değerdir
Dolayısıyla, i değerinde bir kod dönüştürme işlemi gerçekleşir. Bu kod dönüştürme işlemi yalnızca hesaplama süresince gerçekleşir; i değişkeni ise her zaman int türünü korur.
3.4. Programın akışını kontrol eden komutlar
3.4.1. Durdurma
Environment sınıfında tanımlanan Exit yöntemi, bir programın yürütülmesini durdurmaya olanak tanır.
syntaxe void Exit(int status)
action arrête le processus en cours et rend la valeur status au processus père
Exit, devam eden işlemin sonlandırılmasını sağlar ve kontrolü çağıran işleme geri verir. status'in değeri, çağıran işlem tarafından kullanılabilir. DOS altında, bu status değişkeni, değeri bir toplu iş dosyasında test edilebilen ERRORLEVEL sistem değişkenine aktarılır. Unix'te, Bourne Shell komut yorumlayıcısında, status'in değerini alan değişken $?'dir.
programın çalışmasını 0 durum değeriyle durdurur.
3.4.2. Basit seçim yapısı
notlar:
- koşul parantezlerle çevrelenmiştir.
- Her eylem noktalı virgülle biter.
- Küme parantezleri noktalı virgülle bitmez.
- Küme parantezleri, yalnızca birden fazla eylem varsa gereklidir.
- else cümlesi bulunmayabilir.
- then cümlesi yoktur.
Bu yapının algoritmik karşılığı "eğer ... ise ... yoksa" yapısıdır:
![]() |
örnek
if (x>0) { nx=nx+1;sx=sx+x;} else dx=dx-x;
Seçim yapıları iç içe geçirilebilir:
Bazen şu sorun ortaya çıkar:
using System;
namespace Chap1 {
class P07 {
static void Main(string[] args) {
int n = 5;
if (n > 1)
if (n > 6)
Console.Out.WriteLine(">6");
else Console.Out.WriteLine("<=6");
}
}
}
Yukarıdaki örnekte, 10. satırdaki else hangi if ile ilişkilidir? Kural şudur: Bir else her zaman en yakın if'e karşılık gelir; örnekte bu, 8. satırdaki if(n>6),'tir. Başka bir örnek ele alalım:
if (n2 > 1) {
if (n2 > 6) Console.Out.WriteLine(">6");
} else Console.Out.WriteLine("<=1");
Burada else'i if(n2>1)'e atamak istiyorduk, else'i if(n2>6)'e değil. Yukarıdaki açıklamadan dolayı, if(n2>1) {...} else ... ifadesine küme parantezleri eklemek zorundayız.
3.4.3. Durum yapısı
Sözdizimi şu şekildedir:
switch(expression) {
case v1:
actions1;
break;
case v2:
actions2;
break;
. .. .. .. .. ..
default:
actions_sinon;
break;
}
notlar
- switch kontrol ifadesinin değeri bir tamsayı, bir karakter veya bir karakter dizisi olabilir
- kontrol ifadesi parantezlerle çevrelenmiştir.
- default cümlesi bulunmayabilir.
- vi değerleri, ifadenin olası değerleridir. İfadenin değeri vi ise, vi case cümlesinin ardındaki eylemler yürütülür.
- break komutu, case yapısından çıkılmasını sağlar.
- vi değerine bağlı her komut bloğu bir dallanma komutuyla (break, goto, return, ...) sona ermelidir; aksi takdirde derleyici bir hata bildirir.
Örnek
Algoritmik programlamada
selon la valeur de choix
cas 0
fin du module
cas 1
exécuter module M1
cas 2
exécuter module M2
sinon
erreur<--vrai
findescas
C#'da
3.4.4. Tekrar yapıları
3.4.4.1. Tekrar sayısı biliniyor
for yapısı
Sözdizimi şu şekildedir:
for (i=id;i<=if;i=i+ip){
actions;
}
Notlar
- for komutunun 3 argümanı parantez içinde yer alır ve noktalı virgülle ayrılır.
- for'teki her eylem bir noktalı virgülle biter.
- Küme parantezi, yalnızca birden fazla eylem varsa gereklidir.
- Küme parantezinden sonra noktalı virgül gelmez.
Bunun algoritmik karşılığı pour yapısıdır:
bu da tantque yapısına çevrilebilir:
foreach yapısı
Sözdizimi şu şekildedir:
foreach (Type variable in collection)
instructions;
}
Notlar
- collection, sayılabilir bir nesne koleksiyonudur. Zaten bildiğimiz sayılabilir nesne koleksiyonu,
- Type, koleksiyondaki nesnelerin türüdür. Bir dizi için bu, dizinin elemanlarının türü olurdu
- variable, döngüye özgü bir yerel değişkendir ve koleksiyondaki tüm değerleri sırayla alacaktır.
Dolayısıyla aşağıdaki kod:
string[] amis = { "paul", "hélène", "jacques", "sylvie" };
foreach (string nom in amis) {
Console.WriteLine(nom);
}
şunu görüntüler:
3.4.4.2. Tekrar sayısı bilinmiyor
C#'da bu durum için birçok yapı mevcuttur.
While döngüsü
while(condition){
actions;
}
Koşul doğru olduğu sürece döngü devam eder. Döngü hiç çalıştırılmayabilir.
notlar:
- koşul parantezlerle çevrelenmiştir.
- Her eylem noktalı virgülle biter.
- Birden fazla eylem varsa, küme parantezi gereklidir.
- Küme parantezinden sonra noktalı virgül konulmaz.
Buna karşılık gelen algoritmik yapı "tantque" yapısıdır:
(do while) döngüsü
Sözdizimi şöyledir:
do{
instructions;
}while(condition);
Koşul yanlış olana kadar döngü devam eder. Burada döngü en az bir kez gerçekleştirilir.
notlar
- koşul parantezlerle çevrelenmiştir.
- Her eylem noktalı virgülle biter.
- Birden fazla eylem varsa, küme parantezi gereklidir.
- Küme parantezinden sonra noktalı virgül konulmaz.
Buna karşılık gelen algoritmik yapı, "…'ye kadar tekrarla" yapısıdır:
Genel döngü (for) yapısı
Sözdizimi şu şekildedir:
for(instructions_départ;condition;instructions_fin_boucle){
instructions;
}
Koşul doğru olduğu sürece döngü devam eder (her döngü turundan önce değerlendirilir). Instructions_départ, döngüye ilk kez girilmeden önce yürütülür. Instructions_fin_boucle, her döngü turundan sonra yürütülür.
notlar
- instructions_depart ve instructions_fin_boucle içindeki farklı komutlar virgülle ayrılmıştır.
Buna karşılık gelen algoritmik yapı şöyledir:
Örnekler
Aşağıdaki kod parçacıklarının tümü, ilk 10 tam sayının toplamını hesaplar.
int i, somme, n=10;
for (i = 1, somme = 0; i <= n; i = i + 1)
somme = somme + i;
for (i = 1, somme = 0; i <= n; somme = somme + i, i = i + 1) ;
i = 1; somme = 0;
while (i <= n) { somme += i; i++; }
i = 1; somme = 0;
do somme += i++;
while (i <= n);
3.4.4.3. Döngü yönetimi talimatları
for, while, do ... while döngüsünden çıkar. | |
for, while, do ... while döngülerinde bir sonraki yinelemesine geçer |
3.5. İstisna Yönetimi
Birçok C# işlevi istisna, yani hata üretebilir. Bir işlevin istisna üretme olasılığı varsa, programcı hatalara karşı daha dayanıklı programlar elde etmek amacıyla bunu yönetmelidir: Uygulamanın kontrolsüz bir şekilde "çökmesi" her zaman önlenmelidir.
Bir istisnanın yönetimi aşağıdaki şemaya göre gerçekleştirilir:
try{
code susceptible de générer une exception
} catch (Exception e){
traiter l'exception e
}
instruction suivante
İşlev bir istisna oluşturmazsa, bir sonraki komuta geçilir; aksi takdirde, catch cümlesinin gövdesine geçilir ve ardından bir sonraki komuta geçilir. Aşağıdaki noktalara dikkat edilmelidir:
- e, Exception türünde veya bunun türevlerinden bir nesnedir. IndexOutOfRangeException, FormatException, SystemException vb. türleri kullanarak daha spesifik olunabilir: birçok istisna türü mevcuttur. catch (Exception e) yazarak, tüm istisna türlerini yönetmek istediğimizi belirtiriz. try cümlesindeki kodun birden fazla istisna türü oluşturma olasılığı varsa, istisnayı birden fazla catch cümlesiyle yöneterek daha kesin bir tanımlama yapmak isteyebiliriz:
try{
code susceptible de générer les exceptions
} catch ( IndexOutOfRangeException e1){
traiter l'exception e1
}
} catch ( FormatException e2){
traiter l'exception e2
}
instruction suivante
- try/catch maddelerine bir finally maddesi eklenebilir:
try{
code susceptible de générer une exception
} catch (Exception e){
traiter l'exception e
}
finally{
code exécuté après try ou catch
}
instruction suivante
İstisna olsun ya da olmasın, finally maddesinin kodu her zaman yürütülecektir.
- catch cümlesinde, mevcut olan Exception nesnesini kullanmak istemeyebilirsiniz. Bu durumda catch (Exception e){..} yazmak yerine, catch(Exception){...} veya daha basitçe catch {...} yazılır.
- Exception sınıfında, meydana gelen hatayı ayrıntılı olarak açıklayan bir mesaj olan Message özelliği bulunur. Dolayısıyla bunu görüntülemek istersek şunu yazacağız:
catch (Exception ex){
Console.WriteLine("L'erreur suivante s'est produite : {0}",ex.Message);
...
}//catch
- Exception sınıfında, istisnanın türünü ve Message özelliğinin değerini belirten bir karakter dizesi döndüren ToString yöntemi bulunur. Böylece şu şekilde yazabiliriz:
catch (Exception ex){
Console.WriteLine("L'erreur suivante s'est produite : {0}", ex.ToString());
...
}//catch
Şu şekilde de yazılabilir:
Derleyici, {0} parametresine ex.ToString() değerini atayacaktır.
Aşağıdaki örnek, mevcut olmayan bir dizi elemanının kullanılması sonucu ortaya çıkan bir istisnayı göstermektedir:
using System;
namespace Chap1 {
class P08 {
static void Main(string[] args) {
// dizinin tanımlanması ve başlatılması
int[] tab = { 0, 1, 2, 3 };
int i;
// for döngüsüyle dizi görüntüleme
for (i = 0; i < tab.Length; i++)
Console.WriteLine("tab[{0}]={1}", i, tab[i]);
// for each döngüsüyle dizi görüntüleme
foreach (int élmt in tab) {
Console.WriteLine(élmt);
}
// istisna oluşturma
try {
tab[100] = 6;
} catch (Exception e) {
Console.Error.WriteLine("L'erreur suivante s'est produite : " + e);
return;
}//try-catch
finally {
Console.WriteLine("finally ...");
}
}
}
}
Yukarıda, 18. satır bir istisna oluşturacaktır çünkü tab dizisinde 100 numaralı eleman bulunmamaktadır. Programın çalıştırılması aşağıdaki sonuçları verir:
- 9. satır: [System.IndexOutOfRangeException] istisnası oluştu
- 11. satır: Koddaki finally cümlesi (23-25. satırlar) yürütüldü; oysa 21. satırda, yöntemden çıkmak için bir return komutu vardı. finally cümlesinin her zaman yürütüldüğünü unutmayalım.
Aşağıda, bir karakter dizisinin tamsayı türündeki bir değişkene atanması sonucu ortaya çıkan istisnayı, dizinin bir tamsayıyı temsil etmediği durumlarda işleyen başka bir örnek verilmiştir:
using System;
namespace Chap1 {
class P08 {
static void Main(string[] args) {
// örnek 2
// Ad soruluyor
Console.Write("Nom : ");
// cevabın okunması
string nom = Console.ReadLine();
// yaş soruluyor
int age = 0;
bool ageOK = false;
while (!ageOK) {
// soru
Console.Write("âge : ");
// cevabın okunması ve doğrulanması
try {
age = int.Parse(Console.ReadLine());
ageOK = age>=1;
} catch {
}//try-catch
if (!ageOK) {
Console.WriteLine("Age incorrect, recommencez...");
}
}//while
// son sonuç gösterimi
Console.WriteLine("Vous vous appelez {0} et vous avez {1} an(s)",nom,age);
}
}
}
- 15-27. satırlar: bir kişinin yaşını girme döngüsü
- 20. satır: Klavyeden girilen satır, int.Parse yöntemi ile tamsayıya dönüştürülür. Bu yöntem, dönüştürme mümkün değilse bir istisna atar. Bu nedenle işlem bir try / catch bloğu içine alınmıştır.
- 22-23. satırlar: Bir istisna atılırsa, hiçbir işlem yapılmayan catch bloğuna geçilir. Böylece, 14. satırdaki false değerine ayarlanmış ageOK boole değeri, false olarak kalır.
- 21. satır: Bu satıra gelinirse, string -> int dönüşümü başarılı olmuştur. Ancak, elde edilen tamsayının 1'den büyük veya 1'e eşit olduğu kontrol edilir.
- 24-26. satırlar: Yaş yanlışsa bir hata mesajı verilir.
Bazı çalıştırma sonuçları:
3.6. Örnek uygulama - V1
Bir vergi mükellefinin vergisini hesaplamaya yarayan bir program yazmayı hedefliyoruz. Beyan edilecek tek geliri maaşı olan bir vergi mükellefinin basitleştirilmiş durumunu ele alıyoruz (2003 yılı gelirleri için 2004 rakamları):
- evli değilse, çalışanın pay sayısı nbParts=nbEnfants/2 +1 olarak hesaplanır, evliyse nbEnfants/2+2 olarak hesaplanır; burada nbEnfants, çocuk sayısıdır.
- En az üç çocuğu varsa, yarım pay daha alır
- vergilendirilebilir geliri R=0,72*S olarak hesaplanır; burada S, yıllık maaşıdır
- aile katsayısı QF = R/nbParts olarak hesaplanır
- Vergisi I hesaplanır. Aşağıdaki tabloyu ele alalım:
4262 | 0 | 0 |
8382 | 0,0683 | 291,09 |
14753 | 0,1914 | 1322,92 |
23888 | 0,2826 | 2668,39 |
38868 | 0,3738 | 4846,98 |
47932 | 0,4262 | 6883,66 |
0 | 0,4809 | 9505,54 |
Her satırda 3 alan vardır. I vergisini hesaplamak için, QF<=alan1 olan ilk satırı ararız. Örneğin, QF=5000 ise şu satır bulunur
I vergisi bu durumda 0,0683*R - 291,09*nbParts'e eşittir. Eğer QF, QF<=alan1 ilişkisini hiçbir zaman karşılamıyorsa, o zaman son satırdaki katsayılar kullanılır. Burada:
0 0,4809 9505,54
bu da I=0,4809*R - 9505,54*nbParts vergi tutarını verir.
İlgili C# programı şöyledir:
using System;
namespace Chap1 {
class Impots {
static void Main(string[] args) {
// vergi hesaplaması için gerekli veri tabloları
decimal[] limites = { 4962M, 8382M, 14753M, 23888M, 38868M, 47932M, 0M };
decimal[] coeffR = { 0M, 0.068M, 0.191M, 0.283M, 0.374M, 0.426M, 0.481M };
decimal[] coeffN = { 0M, 291.09M, 1322.92M, 2668.39M, 4846.98M, 6883.66M, 9505.54M };
// medeni durumu alıyoruz
bool OK = false;
string reponse = null;
while (!OK) {
Console.Write("Etes-vous marié(e) (O/N) ? ");
reponse = Console.ReadLine().Trim().ToLower();
if (reponse != "o" && reponse != "n")
Console.Error.WriteLine("Réponse incorrecte. Recommencez");
else OK = true;
}//while
bool marie = reponse == "o";
// çocuk sayısı
OK = false;
int nbEnfants = 0;
while (!OK) {
Console.Write("Nombre d'enfants : ");
try {
nbEnfants = int.Parse(Console.ReadLine());
OK = nbEnfants >= 0;
} catch {
}// try
if (!OK) {
Console.WriteLine("Réponse incorrecte. Recommencez");
}
}// while
// maaş
OK = false;
int salaire = 0;
while (!OK) {
Console.Write("Salaire annuel : ");
try {
salaire = int.Parse(Console.ReadLine());
OK = salaire >= 0;
} catch {
}// dene
if (!OK) {
Console.WriteLine("Réponse incorrecte. Recommencez");
}
}// while
// pay sayısının hesaplanması
decimal nbParts;
if (marie) nbParts = (decimal)nbEnfants / 2 + 2;
else nbParts = (decimal)nbEnfants / 2 + 1;
if (nbEnfants >= 3) nbParts += 0.5M;
// vergilendirilebilir gelir
decimal revenu = 0.72M * salaire;
// aile katsayısı
decimal QF = revenu / nbParts;
// QF'e karşılık gelen vergi diliminin aranması
int i;
int nbTranches = limites.Length;
limites[nbTranches - 1] = QF;
i = 0;
while (QF > limites[i]) i++;
// vergi
int impots = (int)(coeffR[i] * revenu - coeffN[i] * nbParts);
// sonuç görüntülenir
Console.WriteLine("Impôt à payer : {0} euros", impots);
}
}
}
- 7-9. satırlar: Sayısal değerlerin decimal türünde olması için sonlarına M (Money) eklenir.
- 16. satır:
- Console.ReadLine() işlevi, klavyeden girilen C1 dizesini
- C1.Trim(), C1'in başındaki ve sonundaki boşlukları kaldırır - C2 dizesini döndürür
- C2.ToLower(), C3 dizesini döndürür; bu, C2 dizesinin tüm harflerinin küçük harfe dönüştürülmüş halidir.
- 21. satır: marie boole değeri, reponse=="o" ilişkisi üzerinden true veya false değerini alır
- 29. satır: Klavyeden girilen dize, int türüne dönüştürülür. Dönüştürme başarısız olursa, bir istisna atılır.
- 30. satır: OK boole değeri, nbEnfants>=0 ilişkisi üzerinden true veya false değerini alır
- 55-56. satırlar: Basitçe nbEnfants/2 yazmak mümkün değildir. Eğer nbEnfants 3'e eş olsaydı, 3/2 elde edilirdi; bu tam sayı bölme işlemi 1,5 değil 1 sonucunu verirdi. Bu nedenle, bölme işleminin operandlarından birini gerçek sayı haline getirmek ve böylece gerçek sayılar arasında bir bölme işlemi elde etmek için (decimal)nbEnfants yazılır.
İşte bazı yürütme örnekleri:
Etes-vous marié(e) (O/N) ? oui
Réponse incorrecte. Recommencez
Etes-vous marié(e) (O/N) ? o
Nombre d'enfants : trois
Réponse incorrecte. Recommencez
Nombre d'enfants : 3
Salaire annuel : 60000 euros
Réponse incorrecte. Recommencez
Salaire annuel : 60000
Impôt à payer : 2959 euros
3.7. Ana programın argümanları
Main ana işlevi, String[] (veya string[]) biçiminde bir dize dizisini parametre olarak kabul edebilir. Bu dizi, uygulamayı başlatmak için kullanılan komut satırındaki argümanları içerir. Dolayısıyla, P programını aşağıdaki (DOS) komutuyla başlatırsak:
P arg0 arg1 … argn
ve Main işlevi şu şekilde tanımlanmışsa:
o zaman args[0]="arg0", args[1]="arg1" … gibi değerler elde edilir. İşte bir örnek:
using System;
namespace Chap1 {
class P10 {
static void Main(string[] args) {
// alınan parametreler listelenir
Console.WriteLine("Il y a " + args.Length + " arguments");
for (int i = 0; i < args.Length; i++) {
Console.Out.WriteLine("arguments[" + i + "]=" + args[i]);
}
}
}
}
Çalıştırılan koda argümanlar aktarmak için şu şekilde ilerlenir:
![]() |
- [1]'te: projeye sağ tıklayın / Properties
- [2]'te: [Debug] sekmesi
- [3]'te: argümanları girin
Çalıştırıldığında şu sonuçlar elde edilir:
Şu imzanın dikkat çekici olduğu belirtilmelidir
, Main işlevi herhangi bir parametre beklemiyorsa geçerlidir.
3.8. Sıralamalar
Bir sıralama, değer alanı bir dizi tamsayı sabitinden oluşan bir veri türüdür. Bir sınavdaki notları yönetmesi gereken bir programı ele alalım. Bunların sayısı beş olacaktır: Passable, AssezBien, Bien, TrèsBien, Excellent.
O halde bu beş sabit için bir sıralama tanımlayabiliriz:
enum Mentions { Passable, AssezBien, Bien, TrèsBien, Excellent };
Dahili olarak, bu beş sabit, ilk sabit için 0, sonraki sabit için 1 ile başlayan ardışık tamsayılarla kodlanır. Bir değişken, bu sıralamadaki değerleri alacağı şekilde tanımlanabilir:
// Mentions numaralandırma listesinden değer alan bir değişken
Mentions maMention = Mentions.Passable;
Bir değişkeni, sıralamanın olası farklı değerleriyle karşılaştırabiliriz:
if (maMention == Mentions.Passable) {
Console.WriteLine("Peut mieux faire");
}
Sıralamanın tüm değerlerini şu şekilde elde edebiliriz:
// dizeler biçiminde etiket listesi
foreach (Mentions m in Enum.GetValues(maMention.GetType())) {
Console.WriteLine(m);
}
Basit tür int'in System.Int32 yapısına eşdeğer olması gibi, basit tür enum de System.Enum yapısına eşdeğerdir. Bu yapı, parametre olarak geçirilen bir sıralı türün tüm değerlerini elde etmeyi sağlayan GetValues adlı statik bir yönteme sahiptir. Bu parametre, bir verinin türü hakkında bilgi içeren bir sınıf olan Type türünde bir nesne olmalıdır. Bir v değişkeninin türü, v.GetType() ile elde edilir. Bir T türünün türü ise typeof(T) ile elde edilir. Dolayısıyla burada maMention.GetType() işlevi, Type nesnesini Mentions ve Enum.GetValues(maMention.GetType()) ise Mentions sıralamasının değerler listesini verir.
Şimdi şunu yazarsak
//etiketlerin tamsayı biçiminde listesi
foreach (int m in Enum.GetValues(typeof(Mentions))) {
Console.WriteLine(m);
}
- satırda, döngü değişkeni tamsayı türündedir. Böylece, sıralamanın değerleri tamsayılar şeklinde elde edilir. Mentions veri türüne karşılık gelen System.Type türündeki nesne, typeof(Mentions) ile elde edilir. Daha önce olduğu gibi maMention.GetType() şeklinde de yazılabilirdi.
Aşağıdaki program, az önce yazılanları örneklemektedir:
using System;
namespace Chap1 {
class P11 {
enum Mentions { Passable, AssezBien, Bien, TrèsBien, Excellent };
static void Main(string[] args) {
// Mentions sıralamasından değer alan bir değişken
Mentions maMention = Mentions.Passable;
// değişken değerinin görüntülenmesi
Console.WriteLine("mention=" + maMention);
// enumerasyon değeriyle test
if (maMention == Mentions.Passable) {
Console.WriteLine("Peut mieux faire");
}
// dizeler biçiminde etiket listesi
foreach (Mentions m in Enum.GetValues(maMention.GetType())) {
Console.WriteLine(m);
}
// bütün sayılar biçiminde etiket listesi
foreach (int m in Enum.GetValues(typeof(Mentions))) {
Console.WriteLine(m);
}
}
}
}
Çalıştırma sonuçları şöyledir:
3.9. Bir fonksiyona parametre aktarımı
Burada, bir fonksiyona parametrelerin nasıl aktarıldığına odaklanacağız. Aşağıdaki statik fonksiyonu ele alalım:
private static void ChangeInt(int a) {
a = 30;
Console.WriteLine("Paramètre formel a=" + a);
}
İşlev tanımında, 1. satırda, a bir biçimsel parametre olarak adlandırılır. Bu parametre, yalnızca changeInt fonksiyonunun tanımlanması amacıyla kullanılmaktadır. Aynı şekilde b olarak da adlandırılabilirdi. Şimdi bu fonksiyonun bir kullanım örneğini ele alalım:
public static void Main() {
int age = 20;
ChangeInt(age);
Console.WriteLine("Paramètre effectif age=" + age);
}
Burada, 3. satırdaki ChangeInt(age) komutunda, age, değerini biçimsel parametre a'e aktaracak olan gerçek parametredir. Burada, bir biçimsel parametrenin bir gerçek parametrenin değerini nasıl aldığına odaklanıyoruz.
3.9.1. Değerle aktarım
Aşağıdaki örnek, bir fonksiyonun parametrelerinin varsayılan olarak değer yoluyla aktarıldığını, yani etkin parametrenin değerinin karşılık gelen biçimsel parametreye kopyalandığını göstermektedir. Burada iki ayrı varlık söz konusudur. Fonksiyon biçimsel parametreyi değiştirirse, etkin parametre hiçbir şekilde değiştirilmez.
using System;
namespace Chap1 {
class P12 {
public static void Main() {
int age = 20;
ChangeInt(age);
Console.WriteLine("Paramètre effectif age=" + age);
}
private static void ChangeInt(int a) {
a = 30;
Console.WriteLine("Paramètre formel a=" + a);
}
}
}
Elde edilen sonuçlar şunlardır:
age etkin parametresinin 20 değeri, a biçimsel parametresine kopyalanmıştır (10. satır). Bu parametre daha sonra değiştirilmiştir (11. satır). Etkin parametre ise değişmeden kalmıştır. Bu aktarım yöntemi, bir fonksiyonun giriş parametreleri için uygundur.
3.9.2. Referansla aktarım
Referansla aktarımda, etkin parametre ve biçimsel parametre tek ve aynı varlıktır. İşlev biçimsel parametreyi değiştirirse, etkin parametre de değiştirilir. C#'da her ikisinin de önüne ref anahtar sözcüğü eklenmelidir:
İşte bir örnek:
using System;
namespace Chap1 {
class P12 {
public static void Main() {
// örnek 2
int age2 = 20;
ChangeInt2(ref age2);
Console.WriteLine("Paramètre effectif age2=" + age2);
}
private static void ChangeInt2(ref int a2) {
a2 = 30;
Console.WriteLine("Paramètre formel a2=" + a2);
}
}
}
ve yürütme sonuçları:
Gerçek parametre, biçimsel parametredeki değişikliği takip etmiştir. Bu aktarım yöntemi, bir fonksiyonun çıkış parametreleri için uygundur.
3.9.3. out anahtar sözcüğüyle referansla aktarım
age2 değişkeninin, changeInt fonksiyonu çağrılmadan önce başlatılmayacağı önceki örneği ele alalım:
using System;
namespace Chap1 {
class P12 {
public static void Main() {
// örnek 2
int age2;
ChangeInt2(ref age2);
Console.WriteLine("Paramètre effectif age2=" + age2);
}
private static void ChangeInt2(ref int a2) {
a2 = 30;
Console.WriteLine("Paramètre formel a2=" + a2);
}
}
}
Bu program derlendiğinde bir hata oluşur:
Bu sorunu, age2 değişkenine bir başlangıç değeri atayarak aşabiliriz. Ayrıca ref anahtar sözcüğünü out anahtar sözcüğüyle de değiştirebiliriz. Böylece, parametrenin yalnızca bir çıkış parametresi olduğunu ve dolayısıyla başlangıç değerine ihtiyaç duymadığını belirtmiş oluruz:
using System;
namespace Chap1 {
class P12 {
public static void Main() {
// örnek 3
int age3;
ChangeInt3(out age3);
Console.WriteLine("Paramètre effectif age3=" + age3);
}
private static void ChangeInt3(out int a3) {
a3 = 30;
Console.WriteLine("Paramètre formel a3=" + a3);
}
}
}
Çalıştırma sonuçları şöyledir:





