Konsol uygulaması
Bu öğreticide size .NET ve C# dilindeki bir dizi özellik öğretildi. Şunları öğreneceksiniz:
- .NET CLI'nın temelleri
- C# Konsol Uygulamasının yapısı
- Konsol G/Ç
- .NET'te Dosya G/Ç API'lerinin temelleri
- .NET'te Görev Tabanlı Zaman Uyumsuz Programlamanın temelleri
Metin dosyasını okuyan ve bu metin dosyasının içeriğini konsola yankılayan bir uygulama oluşturacaksınız. Konsol çıkışı, yüksek sesle okunmasıyla eşleşecek şekilde ilerler. '' (küçüktür) veya '<' (büyüktür) tuşlarına basarak hızı hızlandırabilir veya> yavaşlatabilirsiniz. Bu uygulamayı Windows, Linux, macOS veya Docker kapsayıcısında çalıştırabilirsiniz.
Bu öğreticide birçok özellik vardır. Şimdi bunları tek tek oluşturalım.
Önkoşullar
- .NET 6 SDK.
- Kod düzenleyicisi.
Uygulama oluşturma
İlk adım yeni bir uygulama oluşturmaktır. Bir komut istemi açın ve uygulamanız için yeni bir dizin oluşturun. Bunu geçerli dizin yapın. Komut istemine komutu dotnet new console
yazın. Bu, temel bir "Merhaba Dünya" uygulaması için başlangıç dosyalarını oluşturur.
Değişiklik yapmaya başlamadan önce basit Merhaba Dünya uygulamasını çalıştıralım. Uygulamayı oluşturduktan sonra komut istemine yazın dotnet run
. Bu komut NuGet paketi geri yükleme işlemini çalıştırır, uygulamanın yürütülebilir dosyasını oluşturur ve yürütülebilir dosyayı çalıştırır.
Basit Merhaba Dünya uygulama kodunun tümü Program.cs dosyasındadır. Bu dosyayı sık kullandığınız metin düzenleyiciyle açın. Program.cs dosyasındaki kodu aşağıdaki kodla değiştirin:
namespace TeleprompterConsole;
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
Dosyanın en üstünde bir namespace
deyimine bakın. C#, kullanmış olabileceğiniz diğer Nesne Odaklı diller gibi türleri düzenlemek için ad alanlarını kullanır. Bu Merhaba Dünya programı farklı değildir. Programın ad alanında adıyla TeleprompterConsole
olduğunu görebilirsiniz.
Dosyayı Okuma ve Yankılama
Eklenecek ilk özellik, bir metin dosyasını okuyup tüm bu metni konsolda görüntüleyebilmektir. İlk olarak bir metin dosyası ekleyelim. Bu örneğin GitHub deposundakisampleQuotes.txtdosyasını proje dizininize kopyalayın. Bu, uygulamanız için betik olarak görev yapacaktır. Bu öğretici için örnek uygulamayı indirme hakkında bilgi için Örnekler ve Öğreticiler'deki yönergelere bakın.
Ardından sınıfınıza Program
aşağıdaki yöntemi ekleyin (yönteminin Main
hemen altına):
static IEnumerable<string> ReadFrom(string file)
{
string? line;
using (var reader = File.OpenText(file))
{
while ((line = reader.ReadLine()) != null)
{
yield return line;
}
}
}
Bu yöntem, yineleyici yöntemi olarak adlandırılan özel bir C# yöntemi türüdür. Yineleyici yöntemler, yavaş değerlendirilen dizileri döndürür. Bu, dizideki her öğenin, diziyi kullanan kod tarafından istendiği şekilde oluşturulduğu anlamına gelir. Yineleyici yöntemleri, bir veya daha fazla yield return
deyim içeren yöntemlerdir. yöntemi tarafından ReadFrom
döndürülen nesnesi, dizideki her öğeyi oluşturmaya yönelik kodu içerir. Bu örnekte, kaynak dosyadan sonraki metin satırını okuma ve bu dizeyi döndürmeyi içerir. Çağıran kod diziden bir sonraki öğeyi her istediğinde, kod dosyadan bir sonraki metin satırını okur ve döndürür. Dosya tamamen okunduğunda, sıra başka öğe olmadığını gösterir.
Sizin için yeni olabilecek iki C# söz dizimi öğesi vardır. using
Bu yöntemdeki deyimi kaynak temizlemeyi yönetir. deyiminde başlatılan değişkenin using
(reader
bu örnekte) arabirimini IDisposable uygulaması gerekir. Bu arabirim, Dispose
kaynağın serbest bırakılması gerektiğinde çağrılması gereken tek bir yöntem tanımlar. Derleyici, yürütme deyiminin kapanış küme ayracına ulaştığında bu çağrıyı using
oluşturur. Derleyici tarafından oluşturulan kod, using deyimi tarafından tanımlanan bloktaki koddan bir özel durum oluşturulsa bile kaynağın serbest bırakılmasını sağlar.
reader
değişkeni anahtar sözcüğü kullanılarak var
tanımlanır. var
örtük olarak yazılan bir yerel değişkeni tanımlar. Bu, değişkenin türünün değişkene atanan nesnenin derleme zamanı türü tarafından belirlendiği anlamına gelir. Burada, yönteminden OpenText(String) döndürülen değerdir ve bu bir StreamReader nesnedir.
Şimdi yönteminin dosyasını Main
okumak için kodu dolduralım:
var lines = ReadFrom("sampleQuotes.txt");
foreach (var line in lines)
{
Console.WriteLine(line);
}
Programı çalıştırın (kullanarak dotnet run
) ve konsola yazdırılan her satırı görebilirsiniz.
Gecikmeler ve Biçimlendirme çıkışı ekleme
Sahip olduğunuz şey yüksek sesle okunamayacak kadar hızlı görüntüleniyor. Şimdi çıkıştaki gecikmeleri eklemeniz gerekir. Başlarken, zaman uyumsuz işlemeyi etkinleştiren bazı temel kodları oluşturacaksınız. Ancak, bu ilk adımlar birkaç anti-deseni izler. Siz kodu eklerken açıklamalarda anti-desenler gösterilir ve kod sonraki adımlarda güncelleştirilir.
Bu bölümün iki adımı vardır. İlk olarak, yineleyici yöntemini satırların tamamı yerine tek sözcükler döndürecek şekilde güncelleştireceksiniz. Bu değişikliklerle yapılır. deyimini yield return line;
aşağıdaki kodla değiştirin:
var words = line.Split(' ');
foreach (var word in words)
{
yield return word + " ";
}
yield return Environment.NewLine;
Ardından, dosya satırlarını kullanma şeklinizi değiştirmeniz ve her sözcüğü yazdıktan sonra bir gecikme eklemeniz gerekir. Console.WriteLine(line)
yöntemindeki deyimini Main
aşağıdaki blokla değiştirin:
Console.Write(line);
if (!string.IsNullOrWhiteSpace(line))
{
var pause = Task.Delay(200);
// Synchronously waiting on a task is an
// anti-pattern. This will get fixed in later
// steps.
pause.Wait();
}
Örneği çalıştırın ve çıkışı denetleyin. Şimdi her bir sözcük yazdırılır ve ardından 200 ms gecikme olur. Ancak, kaynak metin dosyasında satır sonu olmadan 80'den fazla karakter içeren birkaç satır bulunduğundan, görüntülenen çıktıda bazı sorunlar gösterilir. Kaydırırken bunu okumak zor olabilir. Bunu düzeltmek kolaydır. Yalnızca her satırın uzunluğunu takip eder ve çizgi uzunluğu belirli bir eşiğe ulaştığında yeni bir çizgi oluşturursunuz. satır uzunluğunu tutan yönteminde bildiriminden words
ReadFrom
sonra bir yerel değişken bildirin:
var lineLength = 0;
Ardından deyiminden yield return word + " ";
sonra (kapanış ayracından önce) aşağıdaki kodu ekleyin:
lineLength += word.Length + 1;
if (lineLength > 70)
{
yield return Environment.NewLine;
lineLength = 0;
}
Örneği çalıştırdığınızda, önceden yapılandırılmış hızıyla sesli okuyabileceksiniz.
Zaman Uyumsuz Görevler
Bu son adımda, çıktıyı bir göreve zaman uyumsuz olarak yazmak için kodu eklerken, metin görünümünü hızlandırmak veya yavaşlatmak ya da metin görünümünü tamamen durdurmak isteyen kullanıcıdan gelen girişleri okumak için başka bir görev çalıştıracaksınız. Bu işlemde birkaç adım vardır ve sonunda ihtiyacınız olan tüm güncelleştirmelere sahip olursunuz. İlk adım, dosyayı okumak ve görüntülemek için oluşturduğunuz kodu temsil eden zaman uyumsuz Task bir dönüş yöntemi oluşturmaktır.
Bu yöntemi sınıfınıza Program
ekleyin (yönteminizin Main
gövdesinden alınır):
private static async Task ShowTeleprompter()
{
var words = ReadFrom("sampleQuotes.txt");
foreach (var word in words)
{
Console.Write(word);
if (!string.IsNullOrWhiteSpace(word))
{
await Task.Delay(200);
}
}
}
İki değişiklik fark edeceksiniz. İlk olarak, yönteminin gövdesinde bir görevin zaman uyumlu bir şekilde bitmesini beklemek için çağırmak Wait() yerine bu sürüm anahtar sözcüğünü await
kullanır. Bunu yapmak için değiştiriciyi async
yöntem imzasına eklemeniz gerekir. Bu yöntem bir Task
döndürür. Nesne Task
döndüren return deyimi olmadığına dikkat edin. Bunun yerine, bu Task
nesne işlecini kullandığınızda await
derleyicinin oluşturduğu kodla oluşturulur. Bu yöntemin bir await
öğesine ulaştığında döndürdüğünü düşünebilirsiniz. Döndürülen Task
, çalışmanın tamamlanmadığını gösterir. Beklenen görev tamamlandığında yöntemi sürdürülür. Tamamlanmak üzere yürütülürken döndürülen Task
, işlemin tamamlandığını gösterir.
Çağıran kod, ne zaman tamamlandığını belirlemek için döndürülen Task
kodu izleyebilir.
çağrısından ShowTeleprompter
önce bir await
anahtar sözcük ekleyin:
await ShowTeleprompter();
Bunun için yöntem imzasını Main
şu şekilde değiştirmeniz gerekir:
static async Task Main(string[] args)
Temel bilgiler bölümünde yöntem hakkında async Main
daha fazla bilgi edinin.
Ardından, Konsoldan okumak için ikinci zaman uyumsuz yöntemi yazmanız ve '' (küçüktür), '<' (büyüktür) ve '>X' veya 'x' anahtarları için watch gerekir. Bu görev için eklediğiniz yöntem aşağıdadır:
private static async Task GetInput()
{
var delay = 200;
Action work = () =>
{
do {
var key = Console.ReadKey(true);
if (key.KeyChar == '>')
{
delay -= 10;
}
else if (key.KeyChar == '<')
{
delay += 10;
}
else if (key.KeyChar == 'X' || key.KeyChar == 'x')
{
break;
}
} while (true);
};
await Task.Run(work);
}
Bu, konsoldan bir anahtar okuyan bir Action temsilciyi temsil eden bir lambda ifadesi oluşturur ve kullanıcı '' (küçüktür) veya '<>' (büyüktür) tuşlarına bastığında gecikmeyi temsil eden bir yerel değişkeni değiştirir. Temsilci yöntemi, kullanıcı 'X' veya 'x' tuşlarına bastığında sona erer ve bu da kullanıcının metin görüntüsünü istediği zaman durdurmasına olanak tanır. Bu yöntem, kullanıcının bir tuşa basmasını engellemek ve beklemek için kullanır ReadKey() .
Bu özelliği tamamlamak için, bu görevlerin (GetInput
ve ) ikisini de başlatan ve ShowTeleprompter
bu iki görev arasındaki paylaşılan verileri yöneten yeni async Task
bir dönüş yöntemi oluşturmanız gerekir.
Bu iki görev arasındaki paylaşılan verileri işleyebilen bir sınıf oluşturmanın zamanı geldi. Bu sınıf iki genel özellik içerir: gecikme ve dosyanın tamamen okunduğunu belirten bir bayrak Done
:
namespace TeleprompterConsole;
internal class TelePrompterConfig
{
public int DelayInMilliseconds { get; private set; } = 200;
public void UpdateDelay(int increment) // negative to speed up
{
var newDelay = Min(DelayInMilliseconds + increment, 1000);
newDelay = Max(newDelay, 20);
DelayInMilliseconds = newDelay;
}
public bool Done { get; private set; }
public void SetDone()
{
Done = true;
}
}
Bu sınıfı yeni bir dosyaya yerleştirin ve gösterildiği gibi bu sınıfı TeleprompterConsole
ad alanına ekleyin. Ayrıca, kapsayan sınıf veya ad alanı adları olmadan ve Max
yöntemlerine başvurabilmeniz Min
için dosyanın en üstüne bir using static
deyim eklemeniz gerekir. Deyimi using static
, yöntemleri bir sınıftan içeri aktarır. Bu, ad alanından tüm sınıfları içeri aktaran olmadan static
deyiminin using
aksinedir.
using static System.Math;
Ardından, yeni config
nesneyi kullanmak için ve GetInput
yöntemlerini güncelleştirmeniz ShowTeleprompter
gerekir. Her iki görevi de başlatmak ve ilk görev tamamlandığında çıkmak için son Task
bir dönüş async
yöntemi yazın:
private static async Task RunTeleprompter()
{
var config = new TelePrompterConfig();
var displayTask = ShowTeleprompter(config);
var speedTask = GetInput(config);
await Task.WhenAny(displayTask, speedTask);
}
Buradaki yeni yöntemlerden biri çağrıdır WhenAny(Task[]) . Bu, bağımsız değişken listesindeki görevlerden herhangi biri tamamlandığında biten bir Task
oluşturur.
Ardından, gecikme için nesnesini kullanmak config
üzere hem ve GetInput
ShowTeleprompter
yöntemlerini güncelleştirmeniz gerekir:
private static async Task ShowTeleprompter(TelePrompterConfig config)
{
var words = ReadFrom("sampleQuotes.txt");
foreach (var word in words)
{
Console.Write(word);
if (!string.IsNullOrWhiteSpace(word))
{
await Task.Delay(config.DelayInMilliseconds);
}
}
config.SetDone();
}
private static async Task GetInput(TelePrompterConfig config)
{
Action work = () =>
{
do {
var key = Console.ReadKey(true);
if (key.KeyChar == '>')
config.UpdateDelay(-10);
else if (key.KeyChar == '<')
config.UpdateDelay(10);
else if (key.KeyChar == 'X' || key.KeyChar == 'x')
config.SetDone();
} while (!config.Done);
};
await Task.Run(work);
}
Bu yeni sürümü ShowTeleprompter
sınıfında yeni bir yöntem TeleprompterConfig
çağırır. Şimdi, yerine öğesini çağırmak RunTeleprompter
ShowTeleprompter
için güncelleştirmeniz Main
gerekir:
await RunTeleprompter();
Sonuç
Bu öğreticide, Konsol uygulamalarında çalışmayla ilgili C# dili ve .NET Core kitaplıkları ile ilgili bazı özellikler gösterilmiştir. Dil ve burada tanıtılan sınıflar hakkında daha fazla bilgi edinmek için bu bilgiyi temel alabilirsiniz. Dosya ve Konsol G/Ç'nin temellerini, Görev tabanlı zaman uyumsuz programlamanın engelleyici ve engelleyici olmayan kullanımını, C# dilinin bir turunu ve C# programlarının nasıl düzenleniyor olduğunu ve .NET CLI'yı gördünüz.
Dosya G/Ç hakkında daha fazla bilgi için bkz. Dosya ve Akış G/Ç. Bu öğreticide kullanılan zaman uyumsuz programlama modeli hakkında daha fazla bilgi için bkz . Görev Tabanlı Zaman Uyumsuz Programlama ve Zaman Uyumsuz programlama.