Skip to content

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:

  1. tamsayılar
  1. gerçek sayılar
  2. ondalık sayılar
  3. karakterler ve karakter dizileri
  4. boole değerleri
  5. 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
Char (S)
karakter
 
2 bayt
Unicode karakter (UTF-16)
string
Dize (C)
karakter dizisi
  
Unicode karakter dizisine referans
int
Int32 (S)
tamsayı
 
4 bayt
[-231, 231-1] [–2147483648, 2147483647]
uint
UInt32 (S)
..
U
4 bayt
[0, 232-1] [0, 4294967295]
long
Int64 (S)
..
L
8 bayt
[-263, 263 -1] [–9223372036854775808, 9223372036854775807]
ulong
UInt64 (S)
..
UL
8 bayt
[0, 264 -1] [0, 18446744073709551615]
sbyte
 
..
 
1 bayt
[-27 , 27 -1] [-128,+127]
byte
Bayt (S)
..
 
1 bayt
[0 , 28 -1] [0,255]
short
Int16 (S)
..
 
2 bayt
[-215, 215-1] [-32768, 32767]
ushort
UInt16 (S)
..
 
2 bayt
[0, 216-1] [0,65535]
float
Tek (S)
gerçek sayı
F
4 bayt
[1.5 10-45, 3.4 10+38] mutlak değer
double
Çift (S)
..
D
8 bayt
[-1.7 10+308, 1.7 10+308] mutlak değer
decimal
Ondalık (S)
ondalık sayı
M
16 bayt
[1.0 10-28,7.9 10+28], 28 anlamlı basamaklı mutlak değer
bool
Boolean (S)
..
 
1 bayt
true, false
object
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:

string nomDuType=3.GetType().FullName;

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:

Type de ent[2] : [System.Int32,4]
Type de fl[10,5]: [System.Single,4]
Type de d[-4,6] : [System.Double,8]
Type de s[essai] : [System.String]
Type de ui[5] : [System.UInt32,4]
Type de l[1000] : [System.Int64,8]
Type de ul[1001] : [System.UInt64,8]
Type de b[5] : [System.Byte,1]
Type de sh[-4] : [System.Int16,2]
Type de ush[10] : [System.UInt16,2]
Type de dec[10,67] : [System.Decimal,16]
Type de b[True] : [System.Boolean,1]

Ekranda C# takma adları yerine .NET türleri görüntülenir.

3.2.2. Sabit verilerin gösterimi

entier int (32 bits)
145, -7, 0xFF (onaltılık)
entier long (64 bits) - suffixe L
100000L
réel double
134,789, -45E-18 (-45 × 10⁻¹⁸)
réel float (suffixe F)
134.789F, -45E-18F (-45 10-18)
réel decimal (suffixe M)
100000M
caractère char
'A', 'b'
chaîne de caractères string
"bugün" "c:\\chap1\\paragraph3" @"c:\chap1\paragraph3"
booléen bool
true, false
date
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:

    const type nom=valeur;          //sabit adı=değer tanımlar

Örneğin:

const float myPI=3.141592F;    

Neden sabitler tanımlanır?

  1. Sabitlere anlamlı isimler verilirse programın okunması daha kolay olur:
    const  float taux_tva=0.186F;
  1. "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:
    const float taux_tva=0.33F;

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:

 Identificateur_de_type variable1[=valeur1],variable2=[valeur2],...;

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 variable1=valeur1,variable2=valeur2,...;

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:

1
2
3
Type de int i=2 : Int32,System.Int32
Type de var j=3 : Int32,System.Int32
Type de var aujourdhui : DateTime,System.DateTime

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 -> chaîne
nombre.ToString()
chaine -> int
int.Parse(dize) veya System.Int32.Parse
chaîne -> long
long.Parse(dize) veya System.Int64.Parse
chaîne -> double
double.Parse (dizi) veya System.Double.Parse (dizi)
chaîne -> float
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:

S=10
S=100000
S=45,78
S=-14,98
S=False
S=10
S=Erreur : Input string was not in a correct format.
S=100
S=Erreur : Input string was not in a correct format.
S=100,87
S=Erreur : Input string was not in a correct format.
S=100,87
S=Erreur : Input string was not in a correct format.

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:

double d1=10.7; 

ama

double d2=int.Parse("10,7");

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:

Type[] tableau[]=new Type[n]

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:

    int[] entiers=new int[] {0,10,20,30};

veya daha basit bir şekilde:

    int[] entiers={0,10,20,30};

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:

    double[,] réels=new double[,] { {0.5, 1.7}, {8.4, -6}};

veya daha basit bir şekilde:

    double[,] réels={ {0.5, 1.7}, {8.4, -6}};

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:

entiers[0]=0
entiers[1]=10
entiers[2]=20
entiers[3]=30
réels[0,0]=0,5
réels[0,1]=1,7
réels[1,0]=8,4
réels[1,1]=-6
noms[0][0]=nom00
noms[1][0]=nom10
noms[1][1]=nom11
noms[2][0]=nom20
noms[2][1]=nom21
noms[2][2]=nom22

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.

  1. klavyeden gelen bilgilerin okunması

  2. bilgilerin işlenmesi

  3. 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:

    string ligne=Console.In.ReadLine();

Console sınıfı, varsayılan olarak In akışına eşleştirilmiş ReadLine yöntemini sunar. Dolayısıyla şu şekilde yazılabilir:

    string ligne=Console.ReadLine();

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
2
3
4
System.Object
i=10
Tapez une ligne : je suis là
ligne=je suis là
  • 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:

  1. standart giriş aygıtı - varsayılan olarak klavyeyi ifade eder ve 0 numaralıdır
  2. standart çıkış aygıtı - varsayılan olarak ekranı belirtir ve 1 numaralıdır
  3. 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 arg1 arg2 .. argn

pg programının argi argümanlarının arkasında, standart G/Ç aygıtlarını dosyalara yeniden yönlendirebiliriz:

0<in.txt
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>out.txt
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
1>>out.txt
aynı şekilde, ancak yazılan veriler out.txt dosyasının mevcut içeriğine eklenir.
2>error.txt
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
2>>error.txt
Aynı şekilde, ancak yazılan veriler error.txt dosyasının mevcut içeriğine eklenir.
1>out.txt 2>error.txt
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
2
3
4
5
6
7
8
...\04\bin\Release>echo test >in.txt
...\04\bin\Release>more in.txt
test
...\04\bin\Release>04 0<in.txt 1>out.txt 2>err.txt
...\04\bin\Release>more out.txt
écriture dans flux Out : test
...\04\bin\Release>more err.txt
écriture dans flux Error : test
  • 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

    V1=V2=expression

işlemi geçerlidir. Öncelik kuralı gereği, en sağdaki = operatörü değerlendirilecektir. Dolayısıyla

    V1=(V2=expression)

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:

    V1=V

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:

V1=V2=....=Vn=expression

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çı:

double Sqrt(double x)
kare kök
double Cos(double x)
kosinüs
double Sin(double x)
Sinüs
double Tan(double x)
Tanjant
double Pow(double x,double y)
x'in y'inci kuvveti (x>0)
double Exp(double x)
Üstel
double Log(double x)
Neper logaritması
double Abs(double x)
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:

double x, y=4;
x=Math.Sqrt(y);

Math sınıfının tam tanımı şöyledir:

Image

Image

Image

Image

Image

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):

[fonctions], [ ( )],[ *, /, %], [+, -]

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.

      bool fin;
      int x=...;
      fin=x>4;

İ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:

espace < .. < '0' < '1' < .. < '9' < .. < 'A' < 'B' < .. < 'Z' < .. < 'a' < 'b' < .. <'z'

İ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:

    "Chat" < "Chaton".

İ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);
        }
    }
}
  1. 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

  1. 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ı:

i=-1, egal=False
chien==chaine1:False,chien!=chaine2:False

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:

  1. !
  2. &&
  3. ||

            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<<n
, i'yi n bit sola kaydırır. Gelen bitler sıfırdır.
i>>n
i'yi n bit sağa kaydırır. i işaretli bir tamsayıysa (signed char, int, long), işaret biti korunur.
i & j
i ve j'nin bit bazında mantıksal OR işlemini gerçekleştirir.
i | j
i ve j'nin bit bazında mantıksal OR işlemini gerçekleştirir.
~i
i'yi 1'e tamamlar
i^j
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:

i=0x0064, j=0xfff3, k=0xf123
i<<4=0x0640, i>>4=0x0006,k>>4=0x0f12,i&j=0x0060,i|j=0xfff7,~i=0xff9b,j<<2=0xffcc,j>>2=0xfffc

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

    expr_cond ? expr1:expr2

ş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

() []  fonction                  
gd
! ~ ++ --                        
dg
new (type) opérateurs cast       
dg
*  /  %                          
gd
+  -                             
gd
<<  >>                           
gd
< <=  > >= instanceof            
gd
==    !=                         
gd
&                                
gd
^                                
gd
|                                
gd
&&                               
gd
||                               
gd
?   :                            
dg
= += -= etc. .                   
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:

    (type) valeur

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ı:

f1=0, f2=0,75

(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.

    Environment.Exit(0);

programın çalışmasını 0 durum değeriyle durdurur.

3.4.2. Basit seçim yapısı

 syntaxe :  if (condition) {actions_condition_vraie;} else {actions_condition_fausse;}

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:

if(condition1)
if (condition2)
        {......}
      else         //koşul2
         {......}
else         //koşul1
     {.......}

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

int choix = 2; 
bool erreur = false;
switch (choix) {
   case 0: return;
   case 1: M1(); break;
   case 2: M2(); break;
   default: erreur = true; break;
}
}// Main sonu

static void M1() {
    Console.WriteLine("M1");
}

static void M2() {
    Console.WriteLine("M2");
}
}

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:

pour i variant de id à if avec un pas de ip
    actions
finpour

bu da tantque yapısına çevrilebilir:

    i  id
    tantque i<=if
        actions
        i i+ip
    fintantque

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:

paul
hélène
jacques
sylvie

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:

tantque condition
    actions
fintantque

(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:

répéter
    actions
jusqu'à condition

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:

instructions_départ
tantque condition
    actions
    instructions_fin_boucle
fintantque

Ö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ı

break
for, while, do ... while döngüsünden çıkar.
continue
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:

catch (Exception ex){
    Console.WriteLine("L'erreur suivante s'est produite : {0}",ex);
    ...
}//catch

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:

tab[0]=0
tab[1]=1
tab[2]=2
tab[3]=3
0
1
2
3
L'erreur suivante s'est produite : System.IndexOutOfRangeException: L'index se trouve en dehors des limites du tableau.
   à Chap1.P08.Main(String[] args) dans C:\data\travail\2007-2008\c# 2008\poly\Chap1\08\Program.cs:satır 7
finally ...
  • 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ı:

1
2
3
Nom : dupont
âge : 23
Vous vous appelez dupont et vous avez 23 an(s)
1
2
3
4
5
6
7
Nom : durand
âge : x
Age incorrect, recommencez...
âge : -4
Age incorrect, recommencez...
âge : 12
Vous vous appelez durand et vous avez 12 an(s)

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

    8382        0.0683        291.09

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) ? o
Nombre d'enfants : 2
Salaire annuel : 60000
Impôt à payer : 4282 euros
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:

public static void Main(string[] args)

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:

1
2
3
4
5
Il y a  4 arguments
arguments[0]=a0
arguments[1]=a1
arguments[2]=a2
arguments[3]=a3

Şu imzanın dikkat çekici olduğu belirtilmelidir

public static void Main()

, 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);
}
  1. 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:

mention=Passable
Peut mieux faire
Passable
AssezBien
Bien
TrèsBien
Excellent
0
1
2
3
4

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:

Paramètre formel a=30
Paramètre effectif age=20

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ı:

Paramètre formel a2=30
Paramètre effectif age2=30

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:

    Use of unassigned local variable 'age2'

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:

Paramètre formel a3=30
Paramètre effectif age3=30