C# Speech Synthesis - Konuşma Sentezleyici

Eğer uygulamanızda, Text-to-Speech (TTS) yeteneği olmasını istiyorsanız, .Net Framework içerisinde bunu yapmanızı sağlayacak sınıflar mevcut.

Projenizde Text-To-Speech sınıflarını kullanabilmek için, System.Speech.Synthesis namespace’indeki sınıflara erişebilmeniz gereklidir.

System.Speech.Synthesis namespace’ine, projenize System.Speech.dll assembly’yi referans olarak ekleyerek ulaşabilirsiniz.

Text-to-Speech kullanmak istediğiniz sınıfın bulunduğu kod dosyasının en üstünde bulunan using‘leri yazdığınız kısma;

using System.Speech.Synthesis;</pre> satırını ekleyiniz. Daha sonra yapmanız gereken, kodunuzun ilgili yerine aşağıdaki kod parçasını eklemek;

SpeechSynthesizer ss = new SpeechSynthesizer();
ss.Speak("Konuşmaya çevrilecek ve hoparlörden duyulacak metin");

Uygulama çalışırken, ilgili satıra geldiğinde, önce Speak() methoduna parametre olarak verdiğiniz string hoparlörden duyulur, sonra bir sonraki satırdan çalışmaya devam eder.

Eğer metnin konuşmaya çevrilme işleminin uzun sürdüğünü ve uygulamanıza “yavaşlık” kattığını düşünüyorsanız, aynı kodu aşağıdaki gibi yazabilirsiniz;

SpeechSynthesizer ss = new SpeechSynthesizer();
ss.SpeakAsync("Konuşmaya çevrilecek ve hoparlörden duyulacak metin");

*SpeakAsync()* method'u sayesinde, uygulama metnin konuşmaya çevrilmesi ve ses kartı aracılığıyla yayınlanması işlemini ayrı bir iş parçacığında gerçekleştirir.

***Not :** Speak() method'u ingilizce kelimeleri doğru olarak okuyor, fakat türkçe kelimeleri okuyamıyor.*

C# String'i Title Case'e (Kelimelerin Baş Harfleri Büyük Gerisi Küçük) Çevirme

.Net Framework içerisinde string.ToUpper() ve string.ToLower() fonksiyonlarını kullanarak string değişkenin içeriğini BÜYÜK ve küçük harfe çevirebiliyoruz.

Metni Upper Case (Tümü Büyük Harfler) ve Lower Case (Tümü Küçük Harfler) formatlamak haricinde Title Case (Kelimelerin Baş Harfleri Büyük Gerisi Küçük) çevirmek yaygın kullanılan başka bir formattır.

string sınıfına bir Extension Method yazarak bu özelliğe sahip olmasını sağlayabiliriz. Extension Method‘u yazarken bilmemiz gereken ilk şey, ToTitleCase() method’unun TextInfo sınıfında yer aldığıdır. TextInfo sınıfına CultureInfo sınıfının CurrentCulture özelliğinden ulaşabiliriz.

public static class ExtensionManager { public static string ToTitleCase(this string Text) { return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(Text); } }</pre>

Artık projemiz içerisinde herhangi bir yerde string değişkenimizin ToTitleCase() method’unu kullanabiliriz.

private void frmMain_Load(object sender, EventArgs e)
{
    string AdSoyad = "engin polat".ToTitleCase();
}


Yukarıdaki kod parçası çalıştığı zaman, *AdSoyad* değişkeninin içeriği **Engin Polat** olacaktır.

***Not :** CultureInfo sınıfının CurrentCulture özelliğinden TextInfo sınıfının özelliklerine eriştiğimiz için, bilgisayarınızda kullandığınız dile göre sonuç farklılık gösterebilir.*

C# Try-Catch-Finally Kod Bloğu Hakkında

Geçen aylarda BilgeAdam‘da bir öğrencimin sorduğu soru geldi aklıma. Soru aslında çok basit, fakat farkettim ki, internette bu konu ile ilgili pek kaynak yok. Bari kendim yazayım dedim. Soru şu;

Bir method’dan geriye true/false değer döndürmem lazım.

Method içerisine yazdığım kodları try-catch-finally blokları içerisine almam gerekiyor.

Eğer try içerisinde hata oluşmazsa, geriye true değer döndüreceğim. Hata oluşur ve kod catch bloğuna girerse false değer döndüreceğim.

Ama finally kod bloğunda yapmam gereken işler var. (Açık bağlantıları kapatmak, vs.)

Eğer try-catch içerisinde return ifadesini kullanırsam, finally bloğundaki kod çalışır mı?</pre> Sorunun doğru cevabı için;

Evet, eğer try-catch-finally ifadesinde try-catch içerisinde return ile method sonlandırılırsa bile, finally bloğundaki kod çalıştırılır.

Hemen bir örnek ile açıklayayım;

public bool OrnekMethod
{
    try
    {
        /// Yapılacak işler
        /// Başarılı olursa;
        return true;
    }
    catch (Exception ex)
    {
        /// Hatayı kaydet, vs.
        return false;
    }
    finally
    {
        ///Açık kaynakların kapatılması, vs. işleri gerçekleştirilir
    }
}

Yukarıdaki örnek'te, **return** ifadesi ile method'dan çıkılmadan önce, **finally** bloğundaki işler gerçekleştirilecektir.

Sql Server Query Plan Cache

Sql Server‘da çalıştırılan her sorgu, aslında çalıştırılmadan önce derleme (compile) işlemine tabi tutulur. Bu derleme işlemi sonucunda Sql Server query plan denilen çıktıyı üretir.

Query Plan, query processor‘e (sorguyu işleyen birim), sorgunun ihtiyaç duyduğu veriler için veritabanında bulunan tablo ve index‘lere fiziksel olarak nasıl erişebileceğini söyler.

Fakat, query plan elde etmek için yapılan bu derleme işlemi, bazı sorgular için çok pahalı olabilir.

Sql Server, aynı sql sorgusunun defalarca çalıştırıldığı durumlarda, derleme işleminin yükünü azaltmak için, query plan cache denilen hafıza bölgesinde query plan‘ları önbellekler.

Query plan cache, önbellekleyeceği sorguları basit bir hash tablo‘da saklar. Hash tablo’nun iki alanı vardır, birinde sql sorgusunun kendisini, diğerinde derleme sonucu ortaya çıkan query plan‘ı saklar.

Sql Server, yeni bir sorgu çalıştıracağı zaman, ilk önce query plan cache‘te sorgunun query plan‘ı var mı diye bakar. Eğer bulursa, daha önce önbelleklenmiş bu query plan‘ı kullanır. Bulamazsa, ilk önce sorguyu yazım denetimine tabi tutar, sonra sorguyu derler ve oluşan query plan‘ı bu listeye ekler.

Query plan cache‘in getirdiği performans artışını ölçmek için, öncelikle Sql Server’daki query plan cache’i boşaltacağız;

DBCC FREEPROCCACHE</pre>

Dikkat : Bu komutu kullandığınızda, Sql Server üzerinde bulunan tüm query plan cache silinir. Veritabanı veya belli bir sorgu için temizleme mümkün değildir. Bu komutun Canlı Veritabanında (Production Database) kullanılmaması önerilir.

Şimdi Sql Server’ın sorguyu inceleme ve derleme işlemi için ne kadar vakit harcadığını bulmamız lazım. Yapmamız gereken, sorguyu çalıştırmadan önce aşağıdaki komutu çalıştırmak;

SET STATISTICS TIME ON

Şimdi sorgumuzu çalıştırabiliriz. Ben Sql Server 2008 için hazırlanmış örnek veritabanında (AdventureWorks 2008R2) aşağıdaki sorguyu çalıştırıyorum;

SELECT * FROM HumanResources.Employee WHERE BusinessEntityId IN (1, 2);

Sorgu sonucu;

SQL Server parse and compile time:
    CPU time = 0 ms, elapsed time = 12 ms.

(2 row(s) affected)

SQL Server Execution Times:
    CPU time = 0 ms,  elapsed time = 1 ms.

Gördüğünüz gibi, sorgunun parse ve compile işlemine tabi tutulması 12 ms. sürdü. Sorgunun çalıştırılması ise 1 ms. sürdü.

Aynı sorguyu tekrar çalıştırırsak, elde edeceğimiz sonuç;

SQL Server parse and compile time:
    CPU time = 0 ms, elapsed time = 1 ms.

(2 row(s) affected)

SQL Server Execution Times:
    CPU time = 0 ms,  elapsed time = 1 ms.


**Query plan cache** sayesinde, **parse** ve **compile** işlemi *12 ms.* yerine *1 ms.* sürdü.

***Not :** Sql Server'ın istatistik toplarken ulaşabileceği en düşük kesinlik süresi 1 ms.'dir. 1 ms.'den kısa süren işler için bile Sql Server 1 ms. raporlar.*

C# İsimsiz Tipler - Anonymous Types

Sadece bir method içerisinde kullanacağınız basit class‘lara kaç defa ihtiyaç duydunuz? Böyle bir class’a her ihtiyaç duyduğunuzda yapmanız gereken, yeni bir class oluşturup, bütün tanımlama kodlarını (private alanlar, public alanlar, vs.) yazmaktır.

C# dili, İsimsiz Tip (Anonymous Type) tanımlamaya izin veriyor. Üstelik, private ve public öğelerin oluşturulmasını ve yönetilmesini C# dilinin kendisi üstleniyor.

public class HataLogla() { var Hata = new { Mesaj = “Hata Mesajının Kendisi”, Tarih = DateTime.Now, Yer = “XClass.YMethod” }; var Kullanici = new { Id = 42, AdSoyad = “Engin Polat”, Yonetici = “Ali Veli” };

string Loglanacak = string.Format("Hata Mesajı: {0}\nTarih: {1} {2}\nHatanın Oluştuğu Yer: {3}\n\nKullanıcıId: {4}\nKullanıcı Adı: {5}\nYöneticisi: {6}", Hata.Mesaj, Hata.ToShortDateString(), Hata.Tarih.ToLongTimeString(), Hata.Yer, Kullanici.Id, Kullanici.AdSoyad, Kullanici.Yonetici);

File.WriteAllText(Loglanacak, @"C:\Log\Log.txt");

MessageBox.Show(Hata.Mesaj, Hata.Tarih); }</pre> Yukarıdaki kodda yer alan *Hata* ve *Kullanici* değişkenlerinin tipleri,** derleme zamanında** derleyici tarafından otomatik oluşturulur. Eğer **method**'un içerisine aşağıdaki kodları eklersek;
MessageBox.Show("Hata değişkeninin tipi : " + Hata.GetType().ToString());
MessageBox.Show("Kullanici değişkeninin tipi : " + Kullanici.GetType().ToString());

Mesaj kutularında şu değerleri görürüz;

Hata değişkeninin tipi : <>f_AnonymousType0’3[System.String,System.DateTime,System.String]

  • Kullanici değişkeninin tipi : <>f_AnonymousType0’3[System.Int32,System.String,System.String]*

Farkettiğiniz gibi, böyle bir tip oluşturmaya çalışırsak, derleme zamanında hata alırız, ama C# derleyicisi bizim için bu tipleri oluşturuyor.

Değişkenin tipini veremeyeceğimiz için, C# diline var anahtar kelimesi eklenmiştir.

var anahtar kelimesi sayesinde, değişkenin tipi atandığı değerden otomatik olarak çözümleniyor.

İsimsiz Tipler (Anonymous Types) IDisposable interface’ini uygulamadığı için, Disposable olamazlar.

Eğer yukarıdaki örneği geleneksel kodlama teknikleri ile yazacak olsaydık;

public class HataBilgi
{
    private string _Mesaj = string.Empty;
    private DateTime _Tarih = DateTime.Now;
    private string _Yer = string.Empty;

    public string Mesaj
    {
        get
        {
            return _Mesaj;
        }
        set
        {
            _Mesaj = value;
        }
    }

    public DateTime Tarih
    {
        get
        {
            return _Tarih;
        }
        set
        {
            _Tarih = value;
        }
    }

    public string Yer
    {
        get
        {
            return _Yer;
        }
        set
        {
            _Yer = value;
        }
    }

    public HataBilgi(string Mesaj, DateTime Tarih, string Yer)
    {
        this.Mesaj = Mesaj;
        this.Tarih = Tarih;
        this.Yer = Yer;
    }
}

public class KullaniciBilgi
{
    private int _Id = 0;
    private string _AdSoyad = string.Empty;
    private string _Yonetici = string.Empty;

    public int Id
    {
        get
        {
            return _Id;
        }
        set
        {
            _Id = value;
        }
    }

    public string AdSoyad
    {
        get
        {
            return _AdSoyad;
        }
        set
        {
            _AdSoyad = value;
        }
    }

    public string Yonetici
    {
        get
        {
            return _Yonetici;
        }
        set
        {
            _Yonetici = value;
        }
    }

    public KullaniciBilgi(int Id, string AdSoyad, string Yonetici)
    {
        this.Id = Id;
        this.AdSoyad = AdSoyad;
        this.Yonetici = Yonetici;
    }
}

public class HataLoglama
{
    HataBilgi Hata = new HataBilgi("Hata Mesajının Kendisi", DateTime.Now, "XClass.YMethod");
    KullaniciBilgi Kullanici = new KullaniciBilgi(42, "Engin Polat", "Ali Veli");

    string Loglanacak = string.Format("Hata Mesajı: {0}\nTarih: {1} {2}\nHatanın Oluştuğu Yer: {3}\n\nKullanıcıId: {4}\nKullanıcı Adı: {5}\nYöneticisi: {6}", Hata.Mesaj, Hata.ToShortDateString(), Hata.Tarih.ToLongTimeString(), Hata.Yer, Kullanici.Id, Kullanici.AdSoyad, Kullanici.Yonetici);

    File.WriteAllText(Loglanacak, @"C:\Log\Log.txt");

    MessageBox.Show(Hata.Mesaj, Hata.Tarih);
}

İsimsiz Tip yeteneklerini kullanarak yazdığımızda ise;

public class HataLogla()
{
    var Hata = new { Mesaj = "Hata Mesajının Kendisi", Tarih = DateTime.Now, Yer = "XClass.YMethod" };
    var Kullanici = new { Id = 42, AdSoyad = "Engin Polat", Yonetici = "Ali Veli" };

    string Loglanacak = string.Format("Hata Mesajı: {0}\nTarih: {1} {2}\nHatanın Oluştuğu Yer: {3}\n\nKullanıcıId: {4}\nKullanıcı Adı: {5}\nYöneticisi: {6}", Hata.Mesaj, Hata.ToShortDateString(), Hata.Tarih.ToLongTimeString(), Hata.Yer, Kullanici.Id, Kullanici.AdSoyad, Kullanici.Yonetici);

    File.WriteAllText(Loglanacak, @"C:\Log\Log.txt");

    MessageBox.Show(Hata.Mesaj, Hata.Tarih);
}

Aradaki fark açıkça ortada!

Engin Polat hakkında

Chief Architect, Microsoft RD, Microsoft MVP

Ada ve Ege'nin babası ;)

Kategoriler

İstatistik

Makale Adedi: 458

Creative Commons Lisansı