見出し画像

C#初心者を卒業しよう(第4回の解答例)


プログラム

Program.cs

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services
    .AddTransient<DistanceService>()
    .AddScoped<ToYards>()
    .AddScoped<IDistance, ToYards>()
    .AddScoped<ToMeters>()
    .AddScoped<IDistance, ToMeters>()
    .AddScoped<MetersToFeet>()
    .AddScoped<IDistance, MetersToFeet>()
    .AddScoped<FeetToMeters>()
    .AddScoped<IDistance, FeetToMeters>();
using IHost host = builder.Build();

var service = host.Services.GetService<DistanceService>() ??
    throw new NotImplementedException(
        "Faild to create 'DistanceService' object.");
service.Run();

public interface IDistance
{
    void Calculate(double distance);
    string CreateAnswerMessage();
}

public enum ConvertNumber
{
    ToYards = 1,
    ToMeters = 2,
    MetersToFeet = 3,
    FeetToMeters = 4,
}

public class DistanceService(IServiceProvider serviceProvider)
{
    public void Run()
    {
        var convertNumber = InputConvertNumber();
        var distanceObject = Create(convertNumber) ??
            throw new NotImplementedException(
                "Faild to create 'IDistance' object.");

        var distance = InputDistance();
        distanceObject.Calculate(distance);

        OutputAnswer(distanceObject);
    }

    protected virtual ConvertNumber InputConvertNumber()
    {
        Console.WriteLine("Please input convert number.");
        Console.WriteLine(
            $"{(int)ConvertNumber.ToYards} : Convert meters to yards.");
        Console.WriteLine(
            $"{(int)ConvertNumber.ToMeters} : Convert yards to meters.");
        Console.WriteLine(
            $"{(int)ConvertNumber.MetersToFeet} : Convert meters to feet.");
        Console.WriteLine(
            $"{(int)ConvertNumber.FeetToMeters} : Convert feet to meters.");
        if (Enum.TryParse(
            typeof(ConvertNumber),
             Console.ReadLine(),
              out var convertNumber))
        {
            return (ConvertNumber)convertNumber;
        }
        throw new FormatException("Invalid input convert number.");
    }

    protected virtual IDistance? Create(ConvertNumber convertNumber)
    {
        switch (convertNumber)
        {
            case ConvertNumber.ToYards:
                return (IDistance?)serviceProvider
                    .GetService(typeof(ToYards));
            case ConvertNumber.ToMeters:
                return (IDistance?)serviceProvider
                    .GetService(typeof(ToMeters));
            case ConvertNumber.MetersToFeet:
                return (IDistance?)serviceProvider
                    .GetService(typeof(MetersToFeet));
            case ConvertNumber.FeetToMeters:
                return (IDistance?)serviceProvider
                    .GetService(typeof(FeetToMeters));
            default:
                throw new ArgumentOutOfRangeException(
                    $"{convertNumber} is out of range.");
        }
    }

    protected virtual double InputDistance()
    {
        Console.WriteLine("Please input distance.");
        if (double.TryParse(Console.ReadLine(), out var distance))
        {
            return distance;
        }
        throw new FormatException("Invalid input distance.");
    }

    protected virtual void OutputAnswer(IDistance distance)
    {
        var outputMessage = distance.CreateAnswerMessage();
        Console.WriteLine(outputMessage);
    }
}

public class Const
{
    public static readonly double METER_TO_YARD = 1.0936133d;
    public static readonly double METER_TO_FOOT = 0.3048d;
}

public class ToYards : IDistance
{
    private double _yards;
    private double _meters;

    public void Calculate(double meters)
    {
        _meters = meters;
        _yards = meters * Const.METER_TO_YARD;
    }

    public string CreateAnswerMessage()
    {
        return $"{_meters} meters is {_yards} yards.";
    }
}

public class ToMeters : IDistance
{
    private double _yards;
    private double _meters;

    public void Calculate(double yards)
    {
        _yards = yards;
        _meters = yards / Const.METER_TO_YARD;
    }

    public string CreateAnswerMessage()
    {
        return $"{_yards} yards is {_meters} meters.";
    }
}

public class MetersToFeet : IDistance
{
    private double _feet;
    private double _meters;

    public void Calculate(double meters)
    {
        _meters = meters;
        _feet = meters / Const.METER_TO_FOOT;
    }

    public string CreateAnswerMessage()
    {
        return $"{_meters} meters is {_feet} feet.";
    }
}

public class FeetToMeters : IDistance
{
    private double _feet;
    private double _meters;

    public void Calculate(double feet)
    {
        _feet = feet;
        _meters = feet * Const.METER_TO_FOOT;
    }

    public string CreateAnswerMessage()
    {
        return $"{_feet} feet is {_meters} meters.";
    }
}

ダウンロード

解説

列挙(enum)に追加する。

public enum ConvertNumber
{
    ToYards = 1,
    ToMeters = 2,
    MetersToFeet = 3,
    FeetToMeters = 4,
}

入力メッセージを追加

        Console.WriteLine(
            $"{(int)ConvertNumber.MetersToFeet} : Convert meters to feet.");
        Console.WriteLine(
            $"{(int)ConvertNumber.FeetToMeters} : Convert feet to meters.");

オブジェクト生成を追加

            case ConvertNumber.MetersToFeet:
                return (IDistance?)serviceProvider
                    .GetService(typeof(MetersToFeet));
            case ConvertNumber.FeetToMeters:
                return (IDistance?)serviceProvider
                    .GetService(typeof(FeetToMeters));

定数を追加

public class Const
{
    public static readonly double METER_TO_YARD = 1.0936133d;
    public static readonly double METER_TO_FOOT = 0.3048d;
}

変換クラスを追加

 メートルをフィートに変換するクラスを追加します。

public class MetersToFeet : IDistance
{
    private double _feet;
    private double _meters;

    public void Calculate(double meters)
    {
        _meters = meters;
        _feet = meters / Const.METER_TO_FOOT;
    }

    public string CreateAnswerMessage()
    {
        return $"{_meters} meters is {_feet} feet.";
    }
}

 フィートをメートルに変換するクラスを追加します。

public class FeetToMeters : IDistance
{
    private double _feet;
    private double _meters;

    public void Calculate(double feet)
    {
        _feet = feet;
        _meters = feet * Const.METER_TO_FOOT;
    }

    public string CreateAnswerMessage()
    {
        return $"{_feet} feet is {_meters} meters.";
    }
}

DI コンテナに登録

 最後に DI コンテナに登録します。

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services
    .AddTransient<DistanceService>()
    .AddScoped<ToYards>()
    .AddScoped<IDistance, ToYards>()
    .AddScoped<ToMeters>()
    .AddScoped<IDistance, ToMeters>()
    .AddScoped<MetersToFeet>()
    .AddScoped<IDistance, MetersToFeet>()
    .AddScoped<FeetToMeters>()
    .AddScoped<IDistance, FeetToMeters>();

using IHost host = builder.Build();

よろしければサポートをお願いします。 いただいたサポートは、書籍代、開発機器購入などに充てさせていただきます。