【C#】interfaceによるデータクラス内の条件分岐(if節)排除

interfaceを継承したクラスだと、非常に簡単にif文を消せます。
複数のデータクラスを扱う場合で、内部にデータクラスを持つ場合と持たない場合とで比較します(**持つ場合は内部にデータクラスの数だけifを配置する必要がある**)。

このことから、interfaceとは一つの責務を持つクラスに実装すべきだということもわかります。

参考

https://qiita.com/peko-thunder/items/4356b381706371f75d7f

https://zenn.dev/ryutaro_h/articles/e02cecca6a82df

# git 

https://github.com/Sheephuman/InterfaceWithoutIF
.net 8.0 Visual Studio 2022
```slim
gsudo
git clone https://github.com/Sheephuman/InterfaceWithoutIF.git
```
:::note info
#### gsudoのインストール

Scoopをインストール

https://qiita.com/Dooteeen/items/12dc8fb14042888113d0

そのあと
```slim
scoop install gsudo
```

:::
まずインターフェースを用意する

# interface
```Cs:IDataContainer.cs
 interface IDataContainer
 {
     string GetData();
 }
 ```
メソッド名```GetData()```を持たせることにより、一つのクラスで分岐させなくても継承先で使用できるようにします。**ただし、やたらとメソッドを追加するとその分、継承先にもメソッドを追加しないといけなくなります**　
C#におけるinterfaceは複数継承が許可されているため、メソッド追加も機能の概念ごとにひとつだけに限定すべきでしょう。
 
 # データクラスその1
 職場女性の名前、身長、３サイズ、相当する羊種など

```Cs:FemaleEmployeeIMPL.cs
public class FemaleEmployeeImpl: IDataContainer
{
    public string EmployeeName { get; set; }
    public int Height { get; set; }
    public (int Bust, int Waist, int Hip) Measurements { get; set; }
    public string? SheepBreed { get; set; }
    
    //雇用データを取得しているかどうかのフラグ
      public bool HasEmployeeData { get; set; } = false;
 

    // コンストラクタ
    public FemaleEmployeeImpl(string employeeName, int height, (int Bust, int Waist, int Hip) measurements, string sheepBreed)
    {
        
        EmployeeName = employeeName ;

        Height = height;
        Measurements = measurements;
        SheepBreed = sheepBreed;
    }

   
         public string GetData()
{

    var emptyData = new EmptyDataContainer();   

    var returnData = HasEmployeeData ? // FemaleEmployeeの場合のデータ表示
    $"名前: {EmployeeName}（身長: {Height}cm）\n" +
           $"3サイズ: B{Measurements.Bust} W{Measurements.Waist}" +
           $" H{Measurements.Hip}\n" +
           $"羊種: {SheepBreed}" : emptyData.GetData() ;


    return returnData;

```

 
 # データクラスその2
 牧場名と飼育頭数、羊飼いの名前、人柄など

```cs:FarmDataImpl.cs
namespace SuperDataClassTest
{
    public class FarmDataImpl:IDataContainer
    {
        public string farmName { get; set; } 
        public int SheepCount { get; set; }
        public string OwnerName { get; set; } 
        public string OwnerPersonality { get; set; }
        public FarmDataImpl? FarmData { get; set; }
        public bool HasFarmData =>  this != null;


        public FarmDataImpl(string _farmName, int sheepCount, string ownerName, string ownerPersonality)
        { 
            farmName = _farmName;

            SheepCount = sheepCount;
            OwnerName = ownerName;
            OwnerPersonality = ownerPersonality;
        }

         public string GetData()
  {
      var emptyData = new EmptyDataContainer();

      string returndata = HasFarmData? $"【牧場データ】\n" +
                           $"牧場名: {farmName}\n" +
                           $"飼育頭数: {SheepCount} 頭\n" +
                           $"牧場主: {OwnerName}（性格: {OwnerPersonality}）"
                           : emptyData.GetData();

      return returndata;
  }
}

```

# Dataを持っていないときのメッセージを持つメソッドクラス

```cs
  class EmptyDataContainer
  {

      public string GetData() => "データがありません";
  }

```


# データクラスのダイアグラム
```mermaid
graph TD;
    IDataContaner --> FarmDataImpl;
    IDataContaner --> FemaleEmployeeImpl;  
```

 # 画面デザイン
~~※わざわざGUIにしなくてもdebug.WrithLine()でいい~~

```Xml

<Window x:Class="SuperDataClassTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:SuperDataClassTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid Grid.Row="1">
        <Grid.RowDefinitions >
            <RowDefinition Height="5*" />
           
        </Grid.RowDefinitions>
        <TabControl>
            <!-- 牧場データ入力タブ -->
            <TabItem Header="牧場データ" Margin="-1,-2,-3,0">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="103*"/>
                        <ColumnDefinition Width="19*"/>
                        <ColumnDefinition Width="672*"/>
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="*"/>
                    </Grid.RowDefinitions>

                    <TextBlock Text="牧場名:" Grid.Row="0" Margin="10,10,10,10" Grid.ColumnSpan="3"/>
                    <TextBox x:Name="FarmNameTextBox" Grid.Row="0" Margin="100,10,10,36" Grid.ColumnSpan="3" Grid.RowSpan="2"/>

                    <TextBlock Text="飼育頭数:" Grid.Row="1" Margin="10,10,10,10" Grid.ColumnSpan="3"/>
                    <TextBox x:Name="SheepCountTextBox" Grid.Row="1" Margin="100,10,10,36" Grid.ColumnSpan="3" Grid.RowSpan="2"/>

                    <TextBlock Text="牧場主の名前:" Grid.Row="2" Margin="10,10,10,10" Grid.ColumnSpan="3"/>
                    <TextBox x:Name="OwnerNameTextBox" Grid.Row="2" Margin="100,10,10,36" Grid.ColumnSpan="3" Grid.RowSpan="2"/>

                    <TextBlock Text="牧場主の性格:" Grid.Row="3" Margin="10,10,10,10" Grid.ColumnSpan="3"/>
                    <TextBox x:Name="OwnerPersonalityTextBox" Grid.Row="3" Margin="100,10,10,40" Grid.ColumnSpan="3" Grid.RowSpan="2"/>

                    <Button Content="登録" Grid.Row="4" Margin="10,10,10,10" Click="RegisterFarmData" Grid.ColumnSpan="3"/>
                    <TextBlock x:Name="FarmOutputTextBlock" Grid.Row="5" Margin="10,10,10,10" TextWrapping="Wrap" Grid.ColumnSpan="3"/>

                </Grid>


            </TabItem>

            <!-- 女性従業員データ入力タブ -->
            <TabItem Header="女性従業員データ">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="*"/>
                    </Grid.RowDefinitions>

                    <TextBlock Text="従業員の名前:" Grid.Row="0" Margin="10"/>
                    <TextBox x:Name="EmployeeNameTextBox" Grid.Row="0" Margin="100,10,10,0"/>

                    <TextBlock Text="身長 (cm):" Grid.Row="1" Margin="10"/>
                    <TextBox x:Name="HeightTextBox" Grid.Row="1" Margin="100,10,10,0"/>

                    <TextBlock Text="バスト:" Grid.Row="2" Margin="10"/>
                    <TextBox x:Name="BustTextBox" Grid.Row="2" Margin="100,10,10,0"/>

                    <TextBlock Text="ウエスト:" Grid.Row="3" Margin="10"/>
                    <TextBox x:Name="WaistTextBox" Grid.Row="3" Margin="100,10,10,0"/>

                    <TextBlock Text="ヒップ:" Grid.Row="4" Margin="10"/>
                    <TextBox x:Name="HipTextBox" Grid.Row="4" Margin="100,10,10,0"/>

                    <TextBlock Text="羊種:" Grid.Row="5" Margin="10"/>
                    <TextBox x:Name="SheepBreedTextBox" Grid.Row="5" Margin="100,10,10,0"/>

                    <Button Content="登録" Grid.Row="6" Margin="10" Click="RegisterEmployeeData"/>
                    <TextBlock x:Name="EmployeeOutputTextBlock" Grid.Row="7" Margin="10" TextWrapping="Wrap"/>
                </Grid>
            </TabItem>
        </TabControl>

    </Grid>
</Window>

```

# 呼び出し(実装)

```cs:
using System.Windows;

namespace SuperDataClassTest;

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window 
{
    public MainWindow()
    {
        InitializeComponent();
    }


    private void RegisterFarmData(object sender, RoutedEventArgs e)
    {
  try
  {

      var farmData = new FarmDataImpl(
      FarmNameTextBox.Text,
      int.Parse(SheepCountTextBox.Text), OwnerPersonalityTextBox.Text,
      OwnerPersonalityTextBox.Text, true);




      FarmOutputTextBlock.Text = farmData.GetData();
  }
  catch (FormatException ex)
  {
      MessageBox.Show("空欄の箇所があります");
      //debug.Writelineも可
  }
}


    private void RegisterEmployeeData(object sender, RoutedEventArgs e)
 {
     try
     {
         // Measurements のタプルを作成
         var measurements = (
       Bust: int.Parse(BustTextBox.Text),
       Waist: int.Parse(WaistTextBox.Text),
       Hip: int.Parse(HipTextBox.Text)
   );


       
            var empleyData = new FemaleEmployeeImpl(EmployeeNameTextBox.Text, int.Parse(HeightTextBox.Text),
                measurements, SheepBreedTextBox.Text, true);

                
            EmployeeOutputTextBlock.Text = empleyData.GetData();
     }
     catch (FormatException ex)
     {
         MessageBox.Show(ex.Message + "空欄の箇所があります");
             //debug.Writelineも可
     
     }
 }
    

```


# 実行結果のスクショ
![bandicam 2025-03-16 20-39-33-501_Harua2.mp4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145714/26f05fad-fda7-4878-b39c-024e4ed9de1c.gif)



#### ※テストデータ入力（真木よう子）
真木よう子
160
84
62
73
ショートヘアひつじ(SP 警視庁警備部警護課第四係)

~~※例外処理書いてないので、空欄で入力すると例外で止まります**~~
めんどいけど書いた



# interfaceを使わずにデータクラスを内部に持つ場合

``GetData()``メソッド一つにまとまる代わりに条件分岐節（if）ができます。
そのうち書きます。

どのデータを入力するかで``GetData()``内の表示内容を変えてますので、if分岐させるよりもコードの保守性が良いと言えるでしょう。

# あとがき
私は入れ子(ネスト)にしたデータクラスも面白いからアリなんじゃないかと思ってるので、好きに使い分けていこうかと思ってます。変数へのアクセスが``hoge.sheepClass.HasEmployee``みたくなるんで嫌だって人も居そうですが。

参考

https://qiita.com/EndOfData/items/91900fd4f2faa9c8807a

まあ確かにinterfaceは便利かもしれない。