3.2.6 Dizileri Bitiştirmek İçin İşleçler + işleci dizeleri (string) birleştirmek için kullanılır. İki veya daha fazla dizeyi birleştirir (peş peşe ekler) ve yeni bir dizge olarak sonuç döndürür. İfadedeki argümanlardan en az biri string türünde ise ve işlenenlerden bazıları string türünde değilse, başarılı olarak dize birleştirmeye izin vermesi için otomatik olarak string türüne dönüştürülür. .NET çalışma zamanı anında bizim için böyle işlem uyumsuzluklarının nasıl işlendiğini düşünmek fantastiktir, bu bize kodlamada biraz zaman tasarrufu ve programlama görevinin ana hedeflerine odaklanmamızı sağlar! Ancak, bir işlemi uygulamak istediğinizde değişkenlerin türünü dönüştürmeye zorlamayı (cast) gözden kaçırmamak iyi bir uygulamadır, gözden kaçırmak yerine, her işlem için uygun türe dönüştürülmüş olmalıdır ki böylece sonuç tam olarak kontrolümüzde olsun ve varsayılan tür dönüşümlerini önlemiş olalım. İşlemlerin türünü dönüştürmek hakkında daha detaylı bilgi bu bölümün ilerisinde "Tür Dönüşümleri" başlıklı bölümde verilecektir.
3.2.6.1 Dizileri Bitiştirmek İçin İşleçler – Örnek İki dizeyi ve bir dizi ile bir dizeyi birleştirmeyi gösteren bir örnek aşağıda verilmiştir:
string csharp = "C#";
string dotnet = ".NET";
string csharpDotNet = csharp + dotnet;
Console.WriteLine(csharpDotNet); // C#.NET
string csharpDotNet4 = csharpDotNet + " " + 5;
Console.WriteLine(csharpDotNet4); // C#.NET 5
Örnekte string türünde iki değişkeni başlatıyoruz ve onlara değer atıyoruz. Üçüncü ve dördüncü satırda biz hem dizeleri bitiştirmek ve sonucu konsolda yazdırmak için Console.WriteLine() yöntemine geçiriyoruz. Sonraki satırda sonuç dizesini bir boşluk karakteri ve 5 sayısı ile bitiştiriyoruz. Döndürülen değeri csharpDotNet5 değişkenine atıyoruz, bu değişkenin türü otomatik olarak string türüne dönüştürülecektir. Son satırda sonucu yazdırıyoruz.
Dizeleri birleştirme (peş peşe ekleme, yapıştırma) yavaş bir işlemdir ve dikkatle kullanılmalıdır. Dizeler üzerinde yapılan döngülü (tekrarlayan) işlemler için StringBuilder sınıfını kullanmanız tavsiye edilir.
I
"Strings" Bölümü’nde bir döngü içinde dizeleri birleştirme işlemleri için neden StringBuilder sınıfının kullanılması gerektiğini ayrıntısıyla anlatacağız. 3.2.7 Bitsel İşleçler Bir bitsel işleç sayısal türlerin ikili gösterimi üzerinde işlem yapan işleçtir. Bilgisayarlardaki tüm veriler ve özellikle sayısal veriler birler ve sıfırların bir dizisi olarak temsil edilir. İkili rakam sistemi bu amaç için kullanılır. Örneğin, 55 sayısı ikili rakam sisteminde 00110111 olarak temsil edilir. Verilerin ikili gösterimi uygundur, çünkü elektronikte sıfır ve bir Boole devreleri tarafından gerçekleştirilebilir, burada sıfır "elektrik yok" olarak yada örneğin –5V gerilim ile temsil edilir ve bir "elektrik var" ile yada örneğin + 5V gerilim ile temsil edilir. İkili rakam sistemini derinlemesine "Sayısal Sistemler" Bölümü’nde inceleyeceğiz, ancak şimdilik bilgisayarlarda sayıların birler ve sıfırlar olarak temsil edildiğini ve bitsel işleçlerin onları analiz etmek ve sıfırları tersine çevirerek bir ve birleri tersine çevirererek sıfır olarak değiştirmek için kullanıldığını düşünebiliriz. Bitsel işleçler mantıksal işleçlere çok benzerdir. Aslında, mantıksal ve bitsel işleçlerin aynı şeyi, ancak farklı veri türlerini kullanarak gerçekleştirdiklerini düşünebiliriz. Mantıksal işleçler, true ve false (Boole değerler) değerler ile çalışırlar, bitsel işleçler sayısal değerler ile çalışır ve bunların ikili temsili üzerinden bit düzeyinde uygulanır, yani bunlar sayıların bitleri (0 ve 1 basamaklarından oluşan) ile çalışır. C# mantıksal işleçleri gibi bitsel işleçler arasında "AND" (&), bitsel "OR" (|), bitsel olumsuzlama (~), ve excluding "OR" (^) vardır.
3.2.7.1 Bitsel İşleçler ve Performansları 0 ve 1 ikili basamakları üzerinde bitsel işleçlerin performansı aşağıdaki tabloda gösterilmektedir:
x
y
~x
x & y
x | y
x ^ y
1
1
0
1
1
0
1
0
0
0
1
1
0
1
1
0
1
1
0
0
1
0
0
0
Gördüğünüz gibi, bitsel ve mantıksal işleçler birbirine çok benziyor. “AND” ve “OR” yazımları açısından aralarındaki fark mantıksal işleçlerin çift işaret (&&) ve çift dikey çubuk (||) ile yazılması, ve bitsel işleçlerin tek bir & simgesi veya dikey çubuk (|) ile yazılmasıdır. Exclusive “OR” için bitsel ve mantıksal işleçler aynıdır "^". Mantıksal olumsuzlama için kullandığımız "!", bitsel olumsuzlamada (evirme) "~" operatörünü kullanır. Programlama için mantıksal operatörlerde hiçbir benzeri olmayan iki bitsel işleç vardır. Bunlar sola bit kaydırma (<<) ve sağa bit kaydırma (>>) olarak tanımlıdır. Sayısal değerler üzerinde kullanılan bu işleçler sola veya sağa tüm bit değerlerini taşırlar. Sayının dışında kalan bitler kaybolur ve 0 ile yer değiştirir. Bit kaydırma işleçleri şu şekilde kullanılır: İşlecin sol tarafında işlecin kullanmak istediği değişkeni (işlenen) yerleştiririz, sağ tarafta kaç bit ofset istediğimizi belirten bir sayısal değeri koyarız. Örneğin, 3 << 2 üç sayısının bitlerini iki kez sola taşımak istediğiniz anlamına gelir. 3 sayısının bitleri şöyledir: "0000 0011". İki kez sola hareket ettirildiğinde, ikili değer şöyle görünecektir: "0000 1100", ve bu bitlerin dizilimi 12 sayısı olacaktır. Örneğe baktığımızda aslında sayıyı 4 ile çarpmış olduğumuzu görebilirsiniz. Bit kaydırmanın kendisi 2’nin bir üssü tarafından çarpma (sola kaydırma) veya bölme (sağa kaydırma) olarak temsil edilebilir. Bu olayın nedeni ikili rakam sisteminin doğasından kaynaklanmaktadır. Sağa hareket ettirmeye örnek 6 >> 2 ile verilirse, bu "0000 0110" ikili sayısını iki pozisyon sağa kaydırmak anlamına gelir. Burada en sağdaki iki basamağı kaybederiz ve sol tarafı sıfır ile besleriz. Sonuç "0000 0001", yani 1 olacaktır.
3.2.7.2 Bitsel İşleçler – Örnek Bitsel işleçlerin kullanımına bir örnek aşağıda verilmiştir. Sayıların ikili gösterimi ve bitsel işleçlerin sonuçları yorumlar (yeşil metin) halinde gösterilmiştir:
byte a = 3; // 0000 0011 = 3
byte b = 5; // 0000 0101 = 5
Console.WriteLine(a | b); // 0000 0111 = 7
Console.WriteLine(a & b); // 0000 0001 = 1
Console.WriteLine(a ^ b); // 0000 0110 = 6
Console.WriteLine(~a & b); // 0000 0100 = 4
Console.WriteLine(a << 1); // 0000 0110 = 6
Console.WriteLine(a << 2); // 0000 1100 = 12
Console.WriteLine(a >> 1); // 0000 0001 = 1
Örneğimizde a ve b değişkenlerini oluşturuyoruz ve ilk değerleri ile başlatıyoruz. Sonra iki değişken üzerinde bazı bitsel işlemlerin sonuçlarını konsola yazdırıyoruz. Uyguladığımız ilk işlem olan "OR" örneği a ve b değişkenlerinin ikili gösterimi içinde 1 olan tüm pozisyonlar için, sonuçta da aynı pozisyonda 1 olduğunu gösteriyor. İkinci işlem "AND" olmuştur. İşlemin sonucunda sadece en sağ bit 1 içeriyor, çünkü a ve b değerlerinin aynı anda 1 olduğu tek pozisyon en sağ bitleridir. Exclusive "OR" sadece a ve b ikili bitlerinin farklı değerlere sahip olduğu pozisyonlarda 1 döndürür. Son olarak, mantıksal olumsuzlama ve bit kaydırma: sola ve sağa gösterilmektedir.
3.2.8 Karşılaştırma İşleçleri C# karşılaştırma işleçleri iki yada daha fazla işleneni karşılaştırmak için kullanılır. C# dili tarafından desteklenen karşılaştırma işleçleri şunlardır:
daha büyük (>)
daha küçük (<)
daha büyük yada eşit (>=)
daha küçük yada eşit (<=)
eşitlik (==)
farklılık (!=)
C# karşılaştırma işleçlerinin tümü ikilidir (iki işlenen alır) ve döndürdükleri sonuç bir Boole değeridir (true veya false). Karşılaştırma işleçleri aritmetik işleçlerden daha düşük önceliğe sahiptir, ancak atama işleçlerinden daha yüksek önceliğe sahiptir.
3.2.8.1 Karşılaştırma İşleçleri – Örnek C# karşılaştırma operatörlerinin kullanımını gösteren bir örnek aşağıda verilmiştir:
Örnekte, ilk olarak x ve y değişkenlerini oluşturuyoruz ve bunlara sırasıyla 10 ve 5 değerlerini atıyoruz. Sonraki satırda Console.WriteLine(...) metotunu kullanarak x ve y değişkenlerinin > işlecinin kullanılmasıyla karşılaştırılmasının sonucunu konsola yazdırıyoruz. x değişkeni, y değişkeninden daha büyük bir değere sahip olduğundan döndürülen değer true olur. Benzer şekilde, x ve y değişkenlerini karşılaştırmak için kullanılan diğer 5 karşılaştırma işlecinden gelen sonuçlar, sonraki satırlarda yazdırılmaktadır.
3.2.9 Atama İşleçleri Bir değişkene değer atamak için kullanılan işleç "=" olarak tanımlıdır (matematiksel denklem karakter). Bir değer atamak için kullanılan sözdizimi aşağıdaki gibidir:
işlenen1 = simgedeğer, ifade veya işlenen2;
3.2.9.1 Atama İşleçleri – Örnek Atama işlecinin kullanımını gösteren bir örnek aşağıda verilmiştir:
int x = 6;
string helloString = "Hello string.";
int y = x;
Örnekte x değişkenine 6 değerini atıyoruz. İkinci satırda helloString değişkenine bir metin simgedeğeri atıyoruz ve üçüncü satırda biz y değişkenine x değişken değerini kopyalıyoruz.
3.2.9.2 Peşpeşe Atama Atama işlemi kademeli olarak kullanılabilir (aynı ifadede bir defadan fazla). Bu durumda, atamalar, sağdan sola doğru arka arkaya gerçekleştirilmektedir. İşte bir örnek:
int x, y, z;
x = y = z = 25;
Örnekte ilk satırda üç değişkeni başlatıyoruz ve ikinci satırda onlara 25 değerini atıyoruz.
C# dilinde tanımlı atama operatörü, "=" iken karşılaştırma operatörü "==" dir. İki işleci değiştirerek kullanmak kod yazma sırasında yapılabilen yaygın bir hatadır. Birbirine çok benzer olan karşılaştırma işlecini ve atama işlecini karıştırmamak için dikkatli olun.
3.2.9.3 Bileşik Atama İşleçleri Atama işleci dışında bileşik atama işleçleri de vardır. Bunlar hem işlem ve hem de atamayı birlikte gerçekleştirecek bir işleç ile kod miktarını azaltmaya yardımcı olurlar. Bileşik operatörler için aşağıdaki sözdizimi vardır:
işlenen1 işleç = işlenen2;
Üstteki ifade aşağıdaki gibidir:
işlenen1 = işlenen1 işleç işlenen2;
Atama yapan bir bileşik işleç örneği aşağıda verilmiştir:
int x = 2;
int y = 4;
x *= y; // Same as x = x * y;
Console.WriteLine(x); // 8
En yaygın olarak kullanılan bileşik atama operatörleri += vardır (işlenen2 değerini işlenen1 değerine ekler), –= (sol işlenenin değerinden sağ işlenen değerini çıkarır). Diğer bileşik atama operatörleri *=, /= ve %= olarak tanımlıdır.
Aşağıdaki örnek bileşik atama işleçlerinin nasıl çalıştığı hakkında iyi bir fikir verir:
int x = 6;
int y = 4;
Console.WriteLine(y *= 2); // 8
int z = y = 3; // y=3 and z=3
Console.WriteLine(z); // 3
Console.WriteLine(x |= 1); // 7
Console.WriteLine(x += 3); // 10
Console.WriteLine(x /= 2); // 5
Örnekte, öncelikle x ve y değişkenlerini oluşturuyoruz ve bunlara sırasıyla 6 ve 4 değerlerini atıyoruz. Sonraki satırda konsola y değişkeni üzerinde *= işleci ve 2 simgedeğeri ile uygulanan işlem sonucunda elde edilen yeni değeri yazdırıyoruz. İşlemin sonucu 8 'dir. Örneğin kalan kısımlarında diğer bileşik atama işleçlerini uyguluyoruz ve konsola sonuçlarını yazdırıyoruz.
3.2.10 Koşullu İşleç ?: Koşullu işleç ?: iki ifadeden hangisinin hesaplanması ve sonuç olarak döndürülmesi gerektiğini belirlemek için bir ifadenin Boole değerini kullanır. Operatör üç işlenen üzerinden çalışır, bu nedenle üçlü işleçtir. Birinci ve ikinci işlenen arasına "?" karakteri yerleştirilir, ve ikinci ve üçüncü işlenen arasına ":" yerleştirilir. İlk işlenen (veya ifade) Boole olmalıdır ve sonraki iki işlenenin aynı türde olması gerekir, sayılar veya dizeleri gibi. ?: işlecinin sözdizimi aşağıdaki gibidir:
işlenen1 ? işlenen2 : işlenen3
Şöyle çalışır: işlenen1true olarak ayarlandıysa, işlecin sonucu işlenen2 değerini döndürür. Aksi halde (işlenen1false olarak ayarlanmış ise), işlecin sonucu işlenen3 değerini döndürür. Çalışma sırasında, ilk argümanın değeri hesaplanır. true değeri varsa, o zaman ikinci (orta) argüman hesaplanır ve sonuç değeri olarak döndürülür. Ancak, ilk argümanın hesaplanan sonucu false ise, o zaman üçüncü (son) argüman hesaplanır ve sonuç değeri olarak döndürülür.
3.2.10.1 Koşullu İşleç "?:" – Örnek "?:" işlecinin kullanımını gösteren bir örnek aşağıda verilmiştir:
int a = 6;
int b = 4;
Console.WriteLine(a > b ? "a>b" : "b<=a"); // a>b
int num = a == b ? 1 : -1; // num will have value -1
3.2.11 Diğer İşleçler Şimdiye kadar aritmetik, mantıksal, bitsel işleçleri, dizeleri bitiştirme işlecini ve ayrıca koşullu işleci ?: inceledik. Bunların yanı sıra C# dilinde tanımlı kayda değer birkaç diğer işleç daha vardır. 3.2.11.1 "." İşleci Erişim işleci "." (nokta) bir sınıf veya nesne yöntemlerine ve veri alanlarına erişmek için kullanılır. Nokta işlecinin kullanım örneği aşağıda verilmiştir:
Console.WriteLine(DateTime.Now); // Prints the date + time
3.2.11.2 [] Kare Köşeli Parantez İşleci Köşeli parantez [] bir dizinin elemanlarına endeks yoluyla erişmek için kullanılır. Dizinleyici olarak adlandırılır. Dizinleyiciler dize karakterlerine erişmek için de kullanılır. Örnek:
int[] arr = { 1, 2, 3 };
Console.WriteLine(arr[0]); // 1
string str = "Hello";
Console.WriteLine(str[1]); // e
3.2.11.3 () Parantez İşleci Parantez () ifadelerin ve işleçlerin yürütme önceliğini geçersiz kılmak için kullanılır. Parantezlerin nasıl çalıştığını daha önce görmüştük.
3.2.11.4 Türü Dönüştürme İşleci Türü dönüştürme işleci (type) bir değişkeni bir türden başka bir türe dönüştürmek için kullanılır. "Türü Dönüştürme" Bölümü’nde ayrıntılı olarak inceleyeceğiz.
3.2.11.5 "as" İşleci Türü dönüştürmek için as işleci de aynı zamanda kullanılır, ancak geçersiz dönüşümler istisnai durum değil, boş değer olan null döndürür.
3.2.11.5 "new" İşleci
Yeni nesneleri oluşturmak ve başlatmak için new işleci kullanılır. "Nesne Oluşturma ve Kullanma" Bölümü’nde ayrıntılı olarak inceleyeceğiz.
3.2.11.6 "is" İşleci Bir nesnenin verilen bir tür ile uyumlu olup olmadığını kontrol etmek için (nesnenin türünü onaylamak için) is işleci kullanılır.
3.2.11.7 "??" İşleci ?? işleci koşullu işlece ?: benzerdir. Farkı iki işlenen arasına yerleştirilmiş olmasıdır ve sadece değeri boş değilse sol işleneni döndürür, aksi takdirde sağ işleneni döndürür. Örnek:
int? a = 5;
Console.WriteLine(a ?? -1); // 5
string name = null;
Console.WriteLine(name ?? "(no name)"); // (no name)
3.2.11.8 Diğer İşleçler – Örnekler Açıkladığımız işleçleri gösteren bir örnek aşağıda verilmiştir:
3.3 Türü Dönüştürme ve Türe Zorlama Genellikle, işleçler aynı veri türüne sahip argümanlar üzerinde çalışır. Ancak C# dilinde tanımlı olan ve belirli bir amaç için en uygununu seçebileceğiniz çok çeşitli veri türleri vardır. Farklı veri türündeki iki değişken üzerinde işlem gerçekleştirmek için her iki değişkenin de aynı veri türüne dönüştürülmesi gerekir. Türü dönüştürme (türezorlama) açık ve örtük olarak yapılabilir. Her C# ifadesinin bir türü vardır. Türü elde etmek için ifadenin yapısına ve türlerine, değişkenlere ve kullanılan simgedeğerlere bakmak gerekir. Geçerli bağlam için uygun olmayan bir türde ifade yazmak mümkündür. Bazı durumlarda bu bir derleme hatası verecektir, fakat diğer durumlarda ifadenin türüne benzer veya ilgili bir tür elde edilebilecektir. Bu durumda program türü dönüştürmeyikapalı olarak gerçekleştirir.
T türünün S türüne spesifik dönüştürülmesinin bir sonucu olarak S türü programın çalıştırılması sırasında T türünün bir ifadesi olarak davranış görür. Bazı durumlarda bu dönüşüm bir doğrulama gerektirecektir. İşte bazı örnekler:
object türünden string türüne dönüşüm değerin gerçekten string türünün bir örneği olduğunu sağlaması için yürütülme zamanında doğrulama gerektirir.
string türünden object türüne dönüşüm herhangi bir doğrulama gerektirmez. string türü object türünün bir kalıtımı olduğu için bir hata veya veri kaybı riski olmadan kendi temel sınıfına dönüştürülebilir. "Nesne Tabanlı Programlama İlkeleri" Bölümü’mde kalıtımı ayrıntılarıyla inceleyeceğiz.
int türünden long türüne dönüşüm yürütülme sırasında doğrulama olmadan yapılabilir, çünkü int türündeki değerler kümesi long türündeki değerler kümesinin bir alt kümesi olduğu için veri kaybı riski yoktur.
double türünden long türüne dönüşüm 64-bit kayan noktalı değerden 64-bit tamsayıya dönüşümü gerektirir. Değerine bağlı olarak, veri kaybı mümkündür ve bu nedenle, türleri açık bir şekilde dönüştürmek gereklidir.
C# dilinde tüm türler diğer tüm türlere dönüştürülemeyebilir, ancak bunlardan sadece bazılarına dönüştürülebilir. Kolaylık sağlamak için, C# dilinin olası bazı dönüştürümlerini kendi türlerine göre üç kategoride gruplayacağız:
3.3.1 Türü Örtük Dönüştürme Türü örtük (kapalı) dönüştürme sadece dönüşüm sırasında veri kaybı riski olmadığı zamanlarda mümkündür, daha düşük bir aralığa sahip türden daha geniş bir aralık türüne dönüştürme yaparken (örneğin int türünden long türüne). Örtük dönüştürme yapmak için herhangi işleci kullanmak gerekli değildir ve dolayısıyla bu dönüşüme örtülü denir. Örtük dönüştürme derleyici tarafından otomatik olarak yapılır daha küçük aralığa sahip ile bir değişkene daha büyük aralıkta değer verdiğinizde yada ifadenin farklı aralığa sahip birkaç türü varsa. Böyle bir durumda, dönüşüm en yüksek aralıktaki tür içine uygulanır. 3.3.1.1 Türü Örtük Dönüştürme – Örnekler Örtülü türü dönüştürmeye bir örnek aşağıda verilmiştir:
int myInt = 5;
Console.WriteLine(myInt); // 5
long myLong = myInt;
Console.WriteLine(myLong); // 5
Console.WriteLine(myLong + myInt); // 10
Örnekte int türünde bir değişken, myInt, oluşturuyoruz ve 5 değerini atıyoruz. Bundan sonra long türünde bir değişken, myLong, oluşturuyoruz ve myInt değişkeninde bulunan değeri buna atıyoruz. mylong değişkeninde depolanan değer otomatik int türünden long türüne dönüştürülür. Son olarak, iki değişkenin toplamından çıkan sonucu yazdırıyoruz. Değişkenler farklı türde olduğu için otomatik olarak daha geniş bir aralıkta olan türe dönüştürülür, yani long türüne ve konsolda yazdırılan sonuç da yine long olur. Gerçekten de, Console.WriteLine() yöntemi için verilen parametre long türündedir, ancak yöntem içinde bu yeniden dönüştürülmüş olacak, bu kez string türüne, böylece konsolda basılabilir. Bu dönüşüm Long.ToString() yöntemi tarafından gerçekleştirilir.
3.3.1.2 Olması Mümkün Örtülü Dönüşümler – Örnekler C# temel veri türleri üzerinde bazı olası örtülü dönüşümler şunlardır:
char → ushort, int, uint, long, ulong, float, double, decimal (char karakter türü olmasına rağmen bazı durumlarda bir sayı olarak kabul edilebilir ve sayısal türde davranış gösterebilir, hatta sayısal ifadelere katılabilir);
uint → long, ulong, float, double, decimal;
int → long, float, double, decimal;
long → float, double, decimal;
ulong → float, double, decimal;
float → double.
Daha küçük bir aralıktaki türden daha büyük aralıktaki türe dönüştürme sırasında hiçbir veri kaybı olmaz. Sayısal değer dönüştürüldükten sonra aynı kalır. Birkaç istisna vardır. int türünden float (32-bit değerlere) türüne dönüştürdüğünüzde, aralarındaki fark int bir tamsayının tüm bitlerini kullanırken float için kesirli bölümü temsil etmede kullanılan bir bit parçasının olmasıdır. Dolayısıyla, int türünden float türüne dönüşüm yapıldığında yuvarlama nedeniyle keskinlik kaybı mümkündür. Aynı şey 64-bitlik long türünün 64-bit uzunluğunda bir double türüne dönüştürülmesi için de geçerlidir.
3.3.2 Türü Açıkça Dönüştürme Veri kaybı olasılığı olduğunda açıkça tür dönüştürme kullanılır. Kayan nokta türünü tamsayı türüne dönüştürürken kesirli bölümünün kaldırılmasıyla gelen veri kaybı her zaman vardır ve türü açıkça dönüştürmek (örneğin, double türünden long türüne) zorunludur. Böyle bir dönüşüm yapmak için veri dönüştürme (type) işlecini kullanmak gereklidir. Aynı zamanda, daha geniş bir aralıktaki türden daha dar bir aralıktaki türe dönüştürürken de veri kaybı olabilir (double türünden floattürüne veya long türünden inttürüne).
3.3.2.1 Türü Açıkça Dönüştürme – Örnek
Türü açıkça dönüştürmenin kullanımını ve bazı durumlarda oluşabilecek veri kaybını gösteren bir örnek aşağıda verilmiştir:
double myDouble = 5.1d;
Console.WriteLine(myDouble); // 5.1
long myLong = (long)myDouble;
Console.WriteLine(myLong); // 5
myDouble = 5e9d; // 5 * 10^9
Console.WriteLine(myDouble); // 5000000000
int myInt = (int)myDouble;
Console.WriteLine(myInt); // -2147483648
Console.WriteLine(int.MinValue); // -2147483648
Örneğin birinci satırında myDouble değişkenine 5.1 değerini atıyoruz. (long) işlecini kullanarak long türüne (açıkça) dönüştürdükten ve konsola myLong değişkenini yazdırdıktan sonra değişkenin kesir kısmını kaybettiğini görüyoruz, çünkü long bir tamsayıdır. Sonra çift duyarlıklı bir gerçek sayı değişkeni olan myDouble için 5 milyar değeri atıyoruz. Son olarak, (int) işleci tarafından myDouble değerini int türüne dönüştürüyoruz ve myInt değişkenini yazdırıyoruz. int.MinValue yazdırmışız gibi aynı sonuç görünmektedir, çünkü myDouble değişkeni int aralığından daha büyük bir değer içeriyor.
Kapsam dışına çıkıldıktan sonra bir değişkenin değerinin ne olacağını tahmin etmek her zaman mümkün değildir! Bu nedenle, yeterince büyük aralıktaki türleri kullanın ve bir "küçük" türlere geçiş yaparken dikkatli olun.
3.3.2.2 Türü Dönüştürme Sırasında Veri Kayıpları Tür dönüşümü sırasında veri kaybı için bir örnek vereceğiz:
long myLong = long.MaxValue;
int myInt = (int)myLong;
Console.WriteLine(myLong); // 9223372036854775807
Console.WriteLine(myInt); // -1
Kasıtlı bir örtük dönüştürme durumunda türü dönüştürme operatörü de kullanılabilir. Bu kod okunabilirliğine katkıda bulunarak hata şansını azaltır ve birçok programcı tarafından iyi bir uygulama olarak kabul edilir. Türü dönüştürmeye verilebilecek biraz daha fazla örnek aşağıda verilmiştir:
Yukarıdaki örnekte son satırda, derleme hatası üretecek bir deyim var, çünkü
double türünü float türüne örtülü ve veri kaybına neden olabilecek şekilde dönüştürmek için çalışıyoruz. C# kesin türlendirmeli bir dil olduğu için bu gibi değerlerin tahsis edilmesine izin vermez.
3.3.2.3 Türe Zorlama Sırasında Taşma İstinasının Fırlatılması Bazen büyük türden küçük türe geçiş sırasında türün taşmasıyla yanlış sonuç almak yerine sorunun bildirimini almak uygundur. Tamsayı türlerinde taşmayı kontrol etmeyi içeren bu anahtar sözcük checked ile tanımlıdır.
double d = 5e9d; // 5 * 10^9
Console.WriteLine(d); // 5000000000
int i = checked((int)d); // System.OverflowException
Console.WriteLine(i);
Yukarıdaki kod parçasının yürütülmesi sırasında OverflowException türünde bir istisnai durum (yani, bir hata bildirimi) ortaya çıkar. İstisnalar ve bunları yakalayan ve işleyen yöntemler hakkında daha fazla bilgiyi "İstisnai Durum İşleme" Bölümü’nde bulabilirsiniz.
3.3.2.4 Olması Mümkün Açık Dönüşümler C# sayısal türleri arasındaki açık dönüşümler aşağıda listelenen türler arasından herhangi ikisi arasında mümkündür:
Bu dönüşümler sırasında sayı boyutu veya hassasiyeti ile ilgili bilgiler gibi birtakım veriler kaybolmuş olabilir. Dikkat ediniz ki, türe zorlama yoluyla string türüne veya türünden dönüştürme mümkün değildir.
3.3.3 String Türüne Dönüştürme Gerekirse null değeri de dahil olmak üzere her türlü veriyi string türüne dönüştürebilirsiniz. Bitiştirme işlecini (+) kullandığınızda argümanlardan en az biri string türünde değilse dizelerin dönüşümü otomatik olarak yapılır. Bu durumda argüman string türüne dönüştürülür ve işleç iki dizenin bitiştirilmiş halini temsil eden yeni bir dize döndürür. Farklı nesneleri string türüne dönüştürmek için başka bir yol da değişken veya değer üzerinde ToString() metotunu çağırmaktır. Bu .NET Framework’ün tüm veri türleri için geçerlidir. Hatta 3.ToString() çağırmak da C# dilinde tamamen geçerlidir ve sonuç "3" dizesini dönecektir.
3.3.3.1 String Türüne Dönüştürme – Örnek Farklı veri türlerini string türüne dönüştüren çeşitli örneklere göz atalım:
int a = 5;
int b = 7;
string sum = "Sum = " + (a + b);
Console.WriteLine(sum);
String incorrect = "Sum = " + a + b;
Console.WriteLine(incorrect);
Console.WriteLine(
"Perimeter = " + 2 * (a + b) + ". Area = " + (a * b) + ".");
Örnekten elde edilen sonuç aşağıdaki gibidir:
Sum = 12
Sum = 57
Perimeter = 24. Area = 35.
Sonuçlardan açıktır ki, bir sayıyı bir karakter dizesine bitiştirmek dizeyi izleyen sayının metin gösterimini sonuçta döndürür. Dikkat ediniz ki, dizeleri bitiştirmek için kullanılan "+", sayıların toplanması işleminde hoş olmayan etkilere neden olabilir, çünkü matematiksel toplama işleci "+" ile eşit önceliğe sahiptir. İşlemlerin öncelikleri parantez içine koyarak değiştirilmediği sürece, her zaman soldan sağa doğru yürütüleceklerdir. Dizeye ve dizeden dönüştürme hakkında daha fazla ayrıntıya "Konsol Giriş ve Çıkış" Bölümü’nde bakacağız.
3.4 İfadeler Programın çalışmasının çoğu ifadelerin hesaplamasında geçer. İfadeler bazı türde (sayı, dize, nesne ya da başka türde) bir değere hesaplanan işleçler, simgedeğişmezler ve değişkenlerden oluşur. İşte ifadelerin bazı örnekleri:
// Expression for calculating the perimeter of the circle
double perimeter = 2 * Math.PI * r;
Console.WriteLine(r);
Console.WriteLine(surface);
Console.WriteLine(perimeter);
Bu örnekte, üç ifade tanımlanmaktadır. İlk ifade bir dairenin yarıçapını hesaplar. İkinci ifade bir dairenin alanını hesaplamaktadır, ve sonuncu ifade çevresini bulur. Yukarıdaki program parçasının sonucu şöyledir:
70
15393.80400259
439.822971502571
3.4.1 İfadelerin Yan Etkileri İfade hesaplanması yan etkiye sebep olabilir, çünkü ifade gömülü atama işleçlerini içerebilir, çağıran yöntemlerin artan veya azalan değerlerine neden olabilir. Böyle bir yan etkinin bir örneği aşağıda verilmektedir:
int a = 5;
int b = ++a;
Console.WriteLine(a); // 6
Console.WriteLine(b); // 6
3.4.2 İfadeler, Veri Türleri ve İşleç Öncelikleri İfadeleri yazarken, veri türü ve kullanılan işleçlerin davranışı dikkate alınmalıdır. Buna önem vermemek beklenmedik sonuçlara yol açabilir. İşte bazı basit örnekler:
// First example
double d = 1 / 2;
Console.WriteLine(d); // 0, not 0.5 // Second example
double half = (double)1 / 2;
Console.WriteLine(half); // 0.5
İlk örnekte, bir ifade iki tamsayıyı bölüyor (1 ve 2 tamsayılarını) ve sonucu double türünde bir değişkene atıyor. Sonuç, bazılarınız için beklenmedik olabilir, ancak onlar bu durumda "/" işlecinin tamsayılar üzerinden çalıştığını ve sonucun kesirli kısmın kesilmesi ile elde edilen bir tamsayı olduğu gerçeğini görmezden gelenlerdir. İkinci örnek gösteriyor ki, sonuçta kesrin de göründüğü bir bölme yapmak istiyorsanız, işlenenlerden en az birinin float veya double türüne dönüştürülmesi gereklidir. Bu senaryoda bölüm sonucu artık tamsayı değildir ve sonuç doğrudur. 3.4.3 Sıfıra Bölme Bir başka ilginç örnek de 0 ile bölünmedir. Programcıların çoğu 0 ile bölünmenin geçersiz işlem olduğunu ve çalışma zamanında bir hataya (istisnai durum) neden olacağını düşünür, ancak bu aslında sadece 0 ile tamsayı bölünmesi için doğrudur. 0 ile kesirsel bölme sonucunun Infinity veya NaN olduğunu gösteren bir örnek aşağıda verilmiştir:
int num = 1;
double denum = 0; // The value is 0.0 (real number)
int zeroInt = (int) denum; // The value is 0 (integer number)
3.4.4 Kodu Daha Anlaşılır Yapmak İçin Parantezlerin Kullanılması İfadeler ile çalışırken işlemlerin öncelikleri hakkında en ufak bir şüphe olduğunda parantez kullanmak önemlidir. Parantezlerin ne kadar yararlı olduğunu gösteren bir örnek aşağıda verilmiştir:
Bir tamsayının tek veya çift olup olmadığını kontrol eden bir ifade yazın.
Belirli bir tamsayının kalansız olarak hem 5 ve hem de 7 tarafından bölünebilir olup olmadığını denetleyen bir Boole ifadesini yazın.
Belirli bir tamsayının (sağdan sola) üçüncü basamağının 7 olup olmadığını kontrol eden bir ifade yazın.
Verilen bir tamsayının üçüncü bitinin 1 veya 0 olup olmadığını kontrol eden bir ifade yazın.
İki tarafı a, b ve yüksekliği h ile verilen bir yamuk alanını hesaplayan bir ifade yazın.
Kullanıcı tarafından girilen kenar ve yükseklik verisine göre bir dikdörtgenin çevresini ve alanını konsola yazdıran bir program yazın.
Ay'ın yerçekimi alanı Dünya'dakinin yaklaşık %17'sidir. Dünya üzerinde belirli bir ağırlığı verilen adamın aydaki ağırlığını hesaplayan bir program yazın.
Belirli bir {x, y} noktasının K({0, 0}, R=5) ile verilen dairenin içinde kalıp kalmadığını denetleyen bir ifade yazın. Açıklama: dairenin merkezi {0, 0} noktası ve yarıçapı 5’tir.
Belirli bir {x, y} noktasının K({0, 0}, R=5) ile verilen dairenin içinde ve [{-1, 1}, {5, 5}] ile verilen dikdörtgenin dışında kalıp kalmadığını denetleyen bir ifade yazın. Açıklama: dikdörtgen için sol alt ve sağ üst köşe verilmiştir.
abcd formatında girdi olarak dört haneli bir sayı alan ve aşağıdaki eylemleri gerçekleştiren bir program yazın (örneğin 2011) :
sayıyı ters sırada konsola yazdıran: dcba (örneğimizde 1102).
son rakamı birinci konuma koyan: dabc (örneğimizde 1201).
ikinci ve üçüncü basamakları yer değiştiren: acbd (örneğimizde 2101).
Bir n sayısı ve p pozisyonu veriliyor. Sayının p pozisyonundaki bit değerini (0 ya da 1) yazdıran işlem dizisini yazın. n = 35, p = 5 -> 1. Başka bir örnek: n = 35, p = 6 -> 0.
v tamsayısının p pozisyondaki bit değerinin 1 olup olmadığını denetleyen bir Boole ifadesini yazın. Örnek v = 5, p = 1 -> false.
Bir n sayısı, v değeri, (v = 0 veya 1) ve p pozisyonu verilmiştir. p pozisyonundaki bit değeri v değerine sahip olacak şekilde n değerini değiştirecek bir işlem dizisi yazın. Örnek: n = 35, p = 5, v = 0 -> n = 3. Başka bir örnek, n = 35, p = 2, v = 1 -> n = 39.
Belirli bir n sayısının (1 < n < 100) asal sayı olup olmadığını denetleyen bir program yazın (yani sadece 1’e ve kendisine kalansız bölünen).
Verilen bir 32-bit işaretsiz tamsayının 3, 4 ve 5’nci pozisyonlarındaki bit değerlerini 24, 25 ve 26’ncı pozisyonlarındaki bit değerleri ile değiştirecek bir program yazın.
Verilen bir 32-bit işaretsiz tamsayının {p, p+1, …, p+k-1} pozisyonlarındaki bit değerlerini {q, q+1, …, q+k-1} pozisyonlarındaki bitler ile değiştirecek bir program yazın.
Bölüm 4. Konsol Giriş ve Çıkış
4.1 Bölümün İçindekileri Bu bölümde veri girişi ve çıkışı için bir araç olarak konsol ile tanışacağız. Ne olduğunu, ne zaman ve nasıl kullanılacağını, ve programlama dillerinin çoğunun konsola nasıl eriştiğini açıklayacağız. C# dili için bazı kullanıcı etkileşimi özellikleri ile tanışacağız: Konsoldan metin ve sayıları okuma ve metin ve sayıları yazdırma. Aynı zamanda giriş-çıkış işlemleri için ana akımları inceleyeceğiz Console.In, Console.Out ve Console.Error, Console ve çeşitli biçimlerde veri yazdırma için biçim dizelerinin kullanımı.
4.2 Konsol Nedir? Konsol işletim sisteminin bir penceresidir, bu pencere vasıtasıyla kullanıcılar işletim sisteminin sistem programları ile veya diğer konsol uygulamaları ile etkileşimde bulunabilirler. Etkileşim standart girdiden (genellikle klavye) metin girişi ile veya standart çıktı (genellikle bilgisayar ekranı) üzerinde metin görüntüleme şeklinde oluşur. Bu eylemler aynı zamanda giriş-çıkış işlemleri olarak bilinir. Konsolda yazılı metin bazı bilgileri getirir ve bir veya daha fazla program tarafından gönderilen bir karakter dizisidir. Her konsol uygulaması için işletim sistemi giriş ve çıkış aygıtlarını bağlar. Varsayılan olarak bunlar klavye ve ekrandır, ancak bir dosya veya diğer cihazlara yönlendirilebilir.
4.2.1 Kullanıcı ve Program Arasındaki İletişim Bir çok program kullanıcı ile bir şekilde iletişim kurar. Programlara talimat vermek amacıyla kullanıcı için bu iletişim gereklidir. Modern iletişim yöntemleri çok ve çeşitlidir: grafik veya web-tabanlıarayüzler, konsol veya diğerleri yoluyla olabilir. Bahsettiğimiz gibi, programlar ve kullanıcılar arasındaki iletişim araçlarından biri de konsoldur. Konsol daha az kullanılır hale gelmektedir. Bunun nedeni, modern kullanıcı arayüzü kavramları ile çalışmanın kullanıcının bakış açısıyla daha uygun ve sezgisel olmasıdır.
4.2.2 Ne Zaman Konsol Kullanılmalıdır? Konsol kullanıcı ile iletişim için bazı durumlarda yeri doldurulamaz bir araç olmaya devam etmektedir. Bu durumlardan biri kullanıcıya sonucun zarif gösteriminden daha çok çözülecek spesifik soruna dikkati odaklamanın gerekli olduğu küçük ve basit programlar yazmaktır. Daha sonra giriş ve çıkış konsolundan giriş yada sonucu çıktı yapan basit bir çözüm kullanılır. Başka bir kullanım da daha büyük bir uygulama için küçük bir kod parçasını test etmek istediğiniz durumdur. Konsol uygulamasının işleminin basitliği nedeniyle karmaşık bir kullanıcı arayüzü üzerinden gitmek zorunda kalmadan ve istediğiniz kodu almak için test için bir dizi ekran geliştirmeden kolayca ve rahatça bu küçük kod parçasını ayırabilirsiniz.
4.2.2 Konsol Nasıl Başlatılır? Her işletim sisteminin konsolu başlatmak için kendi yolu vardır. Windows’da örneğin şu şekilde yapılabilir: Start -> (All) Programs -> Accessories -> Command Prompt Konsolu başlattıktan sonra siyah bir ekran (bu renk değiştirilebilir) aşağıdaki gibi görünmelidir:
Konsolu başlatırken geçerli kullanıcının ev dizini (bu durumda kullanıcı adı nakov) geçerli dizin olarak kullanılır ve bu kullanıcı için bir rehber olarak gösterilir.
Konsol Start düğmesine basmak suretiyle başlatılabilir ve arama kutusuna "cmd" yazıp [Enter] tuşuna basarak (Windows Vista, Windows 7 ve üstünde). Windows XP için, Start->Run … ->, "cmd" yazıp [Enter] dizisi üzerinden gidiniz.
Konsol ekranı yerine sonuçların basitleştirilmiş görüntülenmesi için bu bölümde artık şu formu kullanacağız:
Konsoldan gelen sonuçlar
4.2.3 Konsollar Hakkında Daha Fazlası Sistem konsolu metin bilgilerini görüntüleyen yukarıda gösterilen siyah penceredir. Metin dizelerini gösterir ve her karakter yazdırıldıktan sonra sağa hareket eden bir imlece sahiptir. İmleç konsolun son sütunundan geçtikten sonra (genellikle 80 sütunu vardır), sonraki satırın başına gider. İmleç, son satır üzerinden geçerse, konsolun içeriği yukarı kayar ve son satırın altına yeni boş bir satır gösterir. Windows programları konsol-tabanlı, masaüstü-tabanlı, Web-tabanlı ve diğerleri olabilir. Konsol-tabanlı programlar, giriş ve çıkış için konsolu kullanır. Masaüstü-tabanlı programlar grafik kullanıcı arayüzü (GUI) kullanırlar. Web-tabanlı programların Web-tabanlı kullanıcı arayüzü vardır. Bu kitapta biz hemen hemen her zaman konsol tabanlı programlar yazacağız, böylece girdileri klavyeden okunacak ve çıktıları konsolda yazdırılacaktır. Bazı konsol-tabanlı programlar, kullanıcıların metin, sayı ve diğer verileri girmesini beklerler ve bu genellikle klavye ile yapılır. Windows’da genellikle konsol "Komut İstemi" veya "kabuk" olarak da adlandırılan yada işletim sisteminde işletim sisteminin bir parçası veya ek olarak yüklü olan geniş bir yelpazedeki programların yanı sıra sistem komutlarına erişim sağlayan bir konsol-tabanlı program olan sistem komut yorumlayıcısı ile ilişkilidir. “Kabuk" kelimesi "sargı" anlamına gelmektedir ve kullanıcı ve işletim sisteminin iç kısmı arasında sargı işlevi görür. İşletim sisteminin "kabukları" işletim sistemine sağlayabildikleri arayüzün türüne göre iki ana kategoriye ayrılır:
CLI - Komut Satırı Arabirimi - Komutlar için (Windows’daki cmd.exe ve Linux’daki bash gibi) bir konsoldur.
GUI - Grafik Kullanıcı Arayüzü - (Windows Explorer gibi) grafiksel bir çalışma ortamıdır.
Çoğu yorumlayıcı dosyaları içeren dizinlerin içeriğini incelemek gibi bazı gelişmiş özellikleri desteklemesine rağmen, her iki tür için kabuğun asıl amacı kullanıcının çalıştığı diğer programları yürütmektir.
Her işletim sisteminin kendi komutları olan kendi komut yorumlayıcısı vardır.