CodeBlanks Logo Icon CodeBlanks

Birleştirme

  • C# kursu
  • İleri seviye
  • Ders 83/83
  • 6 dk

Tüm katmanları birleştirerek çalışan bir mini framework yazarsın.

Birleştirme

Son ders tüm parçaları birleştirir. Şu ana kadar komut deseni, async, reflection, öznitelik, DI kabı ve test gördük. Şimdi bir Runner sınıfı ekleyip container'daki tüm komutları sırayla çalıştıracağız.

Runner, Container'ı alır; async Task RunAllAsync() metodu container'daki her komut adını dolaşır, çözer, await cmd.ExecuteAsync() ile çalıştırır ve "{name}: {result}" biçiminde yazdırır. Main artık tek komut değil, tüm kayıtlı komutları çalıştırır. Bu, gerçek bir uygulamanın iskeletidir.

Container'a Names özelliği

Runner'ın tüm komutları dolaşması için container'ın kayıtlı adları dışarı açması gerekir. public IEnumerable<string> Names => _factories.Keys; ile bu sağlanır. IEnumerable<string> yalnızca okuma yapısını vurgular; dışarıdaki kod sözlüğü değiştiremez.

Runner bu Names üzerinde foreach ile dolaşır. Her ad için _container.Resolve<ICommand>(name) çağrısı yapar; sonuç bir ICommand örneğidir. await ile çalıştırır ve çıktıyı yazar. Bu, async + DI + reflection'ın gerçek bir bütün oluşturduğu andır.

Uygulama Runner ve Names ekle

Container sınıfına public IEnumerable<string> Names => _factories.Keys; özelliğini ekle. Runner sınıfı tanımla: kurucu bir Container alsın; public async Task RunAllAsync() metodu _container.Names üzerinde foreach ile dolaşıp her ad için _container.Resolve<ICommand>(name) çağrısı yapsın, await cmd.ExecuteAsync() sonucunu Console.WriteLine($"{name}: {result}") ile yazdırsın. Main'de bir Container yarat, Register("hello", () => new HelloCommand()) ile kayıt yap, bir Runner yarat ve await runner.RunAllAsync() çağır.

Başlangıç kodu

Program.cs
using System;
using System.Threading.Tasks;
using System.Reflection;
using System.Collections.Generic;

[Command("hello")]
class HelloCommand : ICommand
{
    public async Task<string> ExecuteAsync()
    {
        await Task.CompletedTask;
        return "Merhaba";
    }
}

class CommandAttribute : Attribute
{
    public string Name { get; }
    public CommandAttribute(string name) => Name = name;
}

interface ICommand
{
    Task<string> ExecuteAsync();
}

class Container
{
    private readonly Dictionary<string, Func<ICommand>> _factories = new();
    public void Register<T>(string name, Func<T> factory) where T : class, ICommand =>
        _factories[name] = () => factory();
    public T Resolve<T>(string name) where T : class => (T)_factories[name]();
}

class Program
{
    static async Task Main()
    {
        var container = new Container();
        container.Register("hello", () => new HelloCommand());
        TestHelloCommand(container);
        var cmd = container.Resolve<ICommand>("hello");
        Console.WriteLine(await cmd.ExecuteAsync());
    }

    static void TestHelloCommand(Container container)
    {
        var cmd = container.Resolve<ICommand>("hello");
        var result = cmd.ExecuteAsync().Result;
        if (result != "Merhaba")
            throw new Exception($"Beklenen: Merhaba, gerçek: {result}");
        Console.WriteLine("Test passed: hello");
    }
}

Örnek çözüm

Program.cs
using System;
using System.Threading.Tasks;
using System.Reflection;
using System.Collections.Generic;

[Command("hello")]
class HelloCommand : ICommand
{
    public async Task<string> ExecuteAsync()
    {
        await Task.CompletedTask;
        return "Merhaba";
    }
}

class CommandAttribute : Attribute
{
    public string Name { get; }
    public CommandAttribute(string name) => Name = name;
}

interface ICommand
{
    Task<string> ExecuteAsync();
}

class Container
{
    private readonly Dictionary<string, Func<ICommand>> _factories = new();
    public void Register<T>(string name, Func<T> factory) where T : class, ICommand =>
        _factories[name] = () => factory();
    public T Resolve<T>(string name) where T : class => (T)_factories[name]();
    public IEnumerable<string> Names => _factories.Keys;
}

class Runner
{
    private readonly Container _container;
    public Runner(Container container) => _container = container;

    public async Task RunAllAsync()
    {
        foreach (var name in _container.Names)
        {
            var cmd = _container.Resolve<ICommand>(name);
            Console.WriteLine($"{name}: {await cmd.ExecuteAsync()}");
        }
    }
}

class Program
{
    static async Task Main()
    {
        var container = new Container();
        container.Register("hello", () => new HelloCommand());
        var runner = new Runner(container);
        await runner.RunAllAsync();
    }
}

Beklenen çıktı

hello: Merhaba

Uygulama İkinci komut ekle ve çalıştır

Mevcut yapıya ByeCommand : ICommand sınıfını ekle. Sınıf [Command("bye")] ile işaretlensin ve ExecuteAsync() metodu await Task.CompletedTask çağrısı yaparak "Hoşça kal" döndürsün. Main'de container.Register("bye", () => new ByeCommand()) ile ikinci komutu kaydet; Runner her iki komutu sırayla çalıştırsın. Names özelliği sayesinde foreach iki adı da dolaşır.

Başlangıç kodu

Program.cs
using System;
using System.Threading.Tasks;
using System.Reflection;
using System.Collections.Generic;

[Command("hello")]
class HelloCommand : ICommand
{
    public async Task<string> ExecuteAsync()
    {
        await Task.CompletedTask;
        return "Merhaba";
    }
}

class CommandAttribute : Attribute
{
    public string Name { get; }
    public CommandAttribute(string name) => Name = name;
}

interface ICommand
{
    Task<string> ExecuteAsync();
}

class Container
{
    private readonly Dictionary<string, Func<ICommand>> _factories = new();
    public void Register<T>(string name, Func<T> factory) where T : class, ICommand =>
        _factories[name] = () => factory();
    public T Resolve<T>(string name) where T : class => (T)_factories[name]();
    public IEnumerable<string> Names => _factories.Keys;
}

class Runner
{
    private readonly Container _container;
    public Runner(Container container) => _container = container;

    public async Task RunAllAsync()
    {
        foreach (var name in _container.Names)
        {
            var cmd = _container.Resolve<ICommand>(name);
            Console.WriteLine($"{name}: {await cmd.ExecuteAsync()}");
        }
    }
}

class Program
{
    static async Task Main()
    {
        var container = new Container();
        container.Register("hello", () => new HelloCommand());
        var runner = new Runner(container);
        await runner.RunAllAsync();
    }
}

Örnek çözüm

Program.cs
using System;
using System.Threading.Tasks;
using System.Reflection;
using System.Collections.Generic;

[Command("hello")]
class HelloCommand : ICommand
{
    public async Task<string> ExecuteAsync()
    {
        await Task.CompletedTask;
        return "Merhaba";
    }
}

[Command("bye")]
class ByeCommand : ICommand
{
    public async Task<string> ExecuteAsync()
    {
        await Task.CompletedTask;
        return "Hoşça kal";
    }
}

class CommandAttribute : Attribute
{
    public string Name { get; }
    public CommandAttribute(string name) => Name = name;
}

interface ICommand
{
    Task<string> ExecuteAsync();
}

class Container
{
    private readonly Dictionary<string, Func<ICommand>> _factories = new();
    public void Register<T>(string name, Func<T> factory) where T : class, ICommand =>
        _factories[name] = () => factory();
    public T Resolve<T>(string name) where T : class => (T)_factories[name]();
    public IEnumerable<string> Names => _factories.Keys;
}

class Runner
{
    private readonly Container _container;
    public Runner(Container container) => _container = container;

    public async Task RunAllAsync()
    {
        foreach (var name in _container.Names)
        {
            var cmd = _container.Resolve<ICommand>(name);
            Console.WriteLine($"{name}: {await cmd.ExecuteAsync()}");
        }
    }
}

class Program
{
    static async Task Main()
    {
        var container = new Container();
        container.Register("hello", () => new HelloCommand());
        container.Register("bye", () => new ByeCommand());
        var runner = new Runner(container);
        await runner.RunAllAsync();
    }
}

Beklenen çıktı

hello: Merhaba
bye: Hoşça kal

Soru ve cevaplar

Dersin sorularını cevaplarıyla birlikte inceleyebilirsin. Kendini denemek istersen dersi interaktif olarak çöz.

1 Runner.RunAllAsync ne yapar?

  • Komutları siler
  • Yalnızca ilk komutu çalıştırır
  • Yeni komut kaydeder
  • Container'daki tüm komutları sırayla çalıştırır Doğru cevap

Açıklama: RunAllAsync container'daki her komutu sırayla çözer ve çalıştırır.

2 Birleştirme parçalarını eşleştir

Kavram Anlamı
Runner Komutları sırayla çalıştırır
Names Kayıtlı adları açar
RunAllAsync Tüm komutları çalıştırır
foreach Adlar üzerinde dolaşır

İleri seviye bölümündeki tüm dersler