【C#】メモ帳で開発（おまけ：ホスト計算ソフト）

メモ帳を開発はしません、メモ帳で開発します。
自分用覚書その２。

自宅のノートPCがおんぼろなためか、VSC# を動かすとカクカクになってしまうので、やむなくCLI開発。
（※VisualStudio C# 使える人はそっち使った方が絶対に効率良い）

Windows には標準でC#のコンパイラやら何やらが入っているそうなので、それを使って開発していく。


# C#のコンパイラのパスを通す

C#はコンパイル言語なのでコンパイラでコンパイルが必要。
割とパスの通し方忘れるのでメモ。

左下のWindows マークを右クリック。
設定　→　システム　→　詳細情報　→　システムの詳細設定　で、システムのプロパティを開き、「環境変数(N)」を押下。

ユーザーの環境変数もしくは、システムの環境変数の「Path」を選択し、「編集」を押下。
環境変数の編集のウィンドウで「新規(N)」を押下すると、左のリストにあらたにパスを加えられる状態になるので、コンパイラが存在するフォルダを指定。

```cmd
C:¥Windows¥Microsoft.NET¥Framework64¥v4.0.30319¥
```

パスがとっているか、以下のコマンドで確認。
このコンパイラは～～みたいな英文がでたら成功。

```
csc
```


# コマンドプロンプトでソースコードを置くフォルダへ移動

なんかテキトーにフォルダ作ってそこに移動。
（例えばホームディレクトリに csharpProgramというフォルダ）

```
cd C:¥Users¥hemuwan¥csharpProgram
```


てきとーにプログラム書く。メモ帳起動は`notepad`

```
notepad hello.cs
```

別に .txt でもいい。
お試しハローワールドサンプル。

```c#:hello.cs
using System;

class Program
{
  static void Main(string[] args)
  {
    Console.WriteLine("Hello World!");
  }
}
```

上記をコンパイルして実行すると、コンソールに`Hello World`が表示される。

```cmd
csharpProgram>csc hello.cs
csharpProgram>hello.exe
Hello World! 
```

# それなりにいろいろできるよ

フォームを表示させるには、`Main()` の中で、Formクラスを継承したクラスのインスタンスを作成し、`Application.Run()`の引数に入れて使う。

```C#:sample.cs
using System.Windows.Forms;

class Program
{
  static void Main(string[] args)
  {
    Form1 form1 = new Form1();
    Application.Run(form1);
  }
}

class Form1 : Form
{
  
}
```


上記のコードをコンパイルし、.exe ファイルを実行すれば、フォームだけ表示される。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494508/e020cb36-7b5a-f865-abd3-64c2e4c7ffa3.png)

おめでとう、これでメモ帳とコマンドプロンプトを使った
C#の苦行開発環境が出来上がりだよ！

# おまけ、IPアドレスから2進表記と割り当て可能ホスト数を計算してくれるプログラム

せっかくなんで作ってみた。
メーっちゃしんどいのでおとなしく統合開発環境を使うのが吉。

せっかくなので、試行錯誤のコメントもそのまま。
、、、んーしかし、汚い。

```c#:csharpIPConverter.cs
using System;
using System.Windows.Forms;
using System.Drawing;

//Formクラスを継承し、フォーム画面使えるように
class WinMain : Form
{
  public static void Main(string[] args)
  {
    WinMain win = new WinMain();
    win.Text = "IPアドレスを2進数に変換";

    //アプリケーション実行。これでフォームが立ち上がる。
    Application.Run(win);
  }//Main()


  //各部品のインスタンスを作る
  //最初コンストラクタ内で宣言しちゃったから?値の引き渡し失敗した。
  TextBox inputTxt = new TextBox();
  TextBox binTxt = new TextBox();
  TextBox hostCountTxt = new TextBox();
  Button btn1 = new Button();
  Label inputLbl = new Label();  //説明用
  Label binLbl = new Label();
  Label hostCountLbl = new Label();

  //コンストラクタ。フォームの部品などを定義
  //初期値を設定したり
  public WinMain()
  {
    //変数に入れるとき、this を付けた方が明示的か

    //各部品の情報を整える
    inputLbl.Text = "IPアドレスをCIDR表記で入力(例：192.168.1.0/24)";
    inputLbl.Bounds = new Rectangle(10, 10, 250, 20);

    inputTxt.Text = "IPアドレスを入力してください。";
    inputTxt.Bounds = new Rectangle(10, 30, 250, 20);

    btn1.Text = "実行";
    btn1.Bounds = new Rectangle(10, 60, 80, 25);

    binLbl.Text = "2進数に変換すると";
    binLbl.Bounds = new Rectangle(10, 110, 250, 20);

    binTxt.Bounds = new Rectangle(10, 130, 250, 20);

    hostCountLbl.Text = "割り当て可能なホスト数は";
    hostCountLbl.Bounds = new Rectangle(10, 160, 250, 20);

    hostCountTxt.Bounds = new Rectangle(10, 180, 250, 20);

    //ボタンを押して離したときに発動するメソッドを追加
    btn1.MouseUp += new MouseEventHandler(btn1_onclick);

    //部品をフォームに表示
    Controls.Add(inputLbl);
    Controls.Add(inputTxt);
    Controls.Add(btn1);
    Controls.Add(binLbl);
    Controls.Add(binTxt);
    Controls.Add(hostCountLbl);
    Controls.Add(hostCountTxt);    
  }//WinMain() コンストラクタ

  //btn1を押したときのメソッドを定義、名前に決まりはないみたいだけど
  //合わせておいた方がわかり易い。
  public void btn1_onclick(object sender, MouseEventArgs e)
  {
    //入力テキストを受け取り、アドレス計算
    IPaddrConverter(inputTxt.Text);
  }

  void IPaddrConverter(string IPaddress)
  {   
    //変数名、雑すぎてやばい
    string IPaddr = IPaddress;
    string[] ip = IPaddr.Split('/');
    string prefix = ip[1];  //別に代入せんでよかったのでは。

    string[] oxet = ip[0].Split('.');
    for(int i = 0; i < oxet.Length; i++)
      Console.WriteLine(oxet[i]);// 192  168  1  0

    string[] convertOxet = new string[4];

    //2進数に変換した後、
    //00000000.00000000.00000000.00000000の表記にするため、頭に0付けていく
    for(int i = 0; i < oxet.Length; i++)
    {
      convertOxet[i] = Convert.ToString(Convert.ToInt32(oxet[i]), 2);
      if(convertOxet[i].Length < 8)
      {
        //loopCounter にループ回数を代入。
        //最初これをそのままfor文に入れて、値が変わってうまくいかんかった。
        int loopCounter = 8 - convertOxet[i].Length;
        for(int j = 0; j < loopCounter; j++)
        {
          //Console.WriteLine(8 - convertOxet[i].Length);
          convertOxet[i] = "0" + convertOxet[i];
        }
      }           
      Console.WriteLine(convertOxet[i]);
    }

    //192.168.1.0 を 2進数表記 00000000.00000000.00000000.00000000で表示
    //192.168.1.0 -> 11000000.10101000.00000001.00000000
    //Console.WriteLine("{0}", string.Join(".", convertOxet));
    binTxt.Text = string.Join(".", convertOxet);

    //プレフィックス prefix を使って、割り当て可能ホスト数を割り出す。
    //ビットを2進数に直して、それをまた10進に直して、2引くでいこう
    //32 - 24 = 8 -> 8bit = 256 -2 => 割り当て可能ホスト数 254 個 になるはず
    //うまくいかず。。32 - prefix はビットの数なので2進数に変換しても変になる
    //32 - prefix の数ぶん、１　を立てる
    int bitCounter = 32 - int.Parse(prefix);// 32 - 24 = 8
    string hostBit = "";
    for(int i = 0; i < bitCounter; i++)
    {
      hostBit = "1" + hostBit;
    }

    long hostCounter = Convert.ToInt64(hostBit, 2) - 1;
    hostCountTxt.Text = Convert.ToString(hostCounter);
  }
}//class WinMain : Form
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494508/a2a7c9b0-c141-c774-24c8-c92f61e53a60.png)

xxx.xxx.xxx.xxx/xx の表記で入力してね。
違うとバグるよ。