読者です 読者をやめる 読者になる 読者になる

プログラミング素人のArduino

技術屋の末端。プログラミングは専門外。 電気回路も専門外です。 コードに間違いなど見つけられたら、気軽にコメントください。 VC#始めました。

C# でテキストファイルスクレイピング

ウェブスクレイピングという言葉がありますが、これはウェブ(特定のHP上)から必要な情報を取り出すものです。
www.fascinatedwithtofu.com

仕事(電子機器開発)上で機械の動作ログがテキストで出てくるのですが、これを解析するのに通常はExcelのマクロで行っています。
機能としては十分なことが可能なのですが、実行速度が遅い。

ここで、これをC#で作ってみようと思いました。
StreamReaderをつかえばできそうなことは容易に想像がつきます。
結果的にはExcel VBAより高速に抽出が完了します。
また、VBAの場合はファイルの読み込み中に他のExcelでの作業ができませんが(できなくもないけど)C#で作れば、Excelのプロセスが使われるわけではないのでExcelの作業を止めることもありません。

UIとしては↓のようなものを作成し、「Target / URL」ボックスは今後作るウェブスクレイピング向け。
Kyewordに目的のIndexを入れて「File」クリックで実行します。
f:id:s51517765:20170430122815j:plain

<命名ルール>
デザイナーは敢えて公開しませんが、
ボタンクリックイベントは
「ボタン名_Click」 →ex) private void FileOpen_Click …
チェックボックスの状態はチェックボックスのDefaolt名がcheckBox(Number)だと思うので、checkBoxという名前を残して、
「checkBox名称」 → ex) checkBoxPreview
コンボボックスなら「comboBox名称」→ ex) comboBoxKeyword
というようにつけていくと後々わかりやすいのではないかと思います。
もっといい方法(きちんとした命名ルール)があるかもしれなくて、自作の方法ですが。

<機能>
・テキストまたはそれに準ずるファイルを読み込むことができる。
・Keywordが含まれている「行」を抽出しTextファイルに出力する。
・Previewボックスに出すこともできる。
・上記2つの出力先はチェックボックスで切り替え可能。
・上記チェックボックスがいずれもチェックされていないときはErrorをだす。
・読み込み中は読み込みが実行中であることを示す。(今回はPreviewボックスのグレーアウトと、ボタンの無効化)
・Previewボックスには読み込みが続けて行われても、区別できるようにする(今回は読み込み開始時刻をいれる)
・使用許諾に了承しない人には使わせない

<ロジック設計>
プログラムを実行するにはそのプログラムが正しく動作する条件が必要です。
まず捜索するKeywordが必要です。これがないときは基本的にはErrorです。
しかし、「Blank」というのもありといえばあり。
出力条件はそのプログラムの実行結果の出力なので、これがないとなにも意味を成しません。
この条件判断はなくてもErrorが出るわけではありませんが、その他のErrorがあるのか、本当に動作した結果何も出力がないのか、の判断がつかないのは困るので入れておくほうがいいと考えられます。
f:id:s51517765:20170430132003j:plain

<実行結果>
テスト用の題材としてはWikipediaのあるページのHTMLソースをテキストに保存したものを使いました。
例えば、"<h" をKeywordにすると、<h1、<h2、<h3…などの含まれた行だけを取り出すことができます。
f:id:s51517765:20170430182103j:plain

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Collections;

namespace mojiretsu
{
    public partial class Form1 : System.Windows.Forms.Form
    {

        private void Form1_Load(object sender, EventArgs e)
        {

            Boolean UserSet = false;
            var listKeyword = "";
            try
            {
                StreamReader srKeyword = new StreamReader("ListKeyword.txt");
                while ((listKeyword = srKeyword.ReadLine()) != null)      // ストリームの末尾まで繰り返す
                {
                    if (listKeyword != "123456789012")
                    {
                        comboBoxKeyword.Items.Add(listKeyword);
                    }
                    else
                    {
                        UserSet = true;
                    }
                }
            }
            catch
            {
                MessageBox.Show("Keyword List is not found, and make it.");
                using (System.IO.FileStream hStream = System.IO.File.Create("ListKeyword.txt"))
                {
                    // 作成時に返される FileStream を利用して閉じる
                    if (hStream != null)
                    {
                        hStream.Close();
                    }
                }
            }

            if (UserSet == false)
            {
                if (MessageBox.Show("The producer does not compensate for any damage using this software.", "License confirmation", MessageBoxButtons.OKCancel) != DialogResult.OK)
                {
                    MessageBox.Show("Not agree and can not use this.");
                    Close();
                }
            }
        }

        String Keyword;

        public Form1()
        {
            InitializeComponent();
        }

        private void FileOpen_Click(object sender, EventArgs e)
               {
            if (textBoxURL.Text == "")
            {
                if (keywordCheck() == true)
                {
                    if (writeOutCheck() == true)
                    {

                        FileOpen();
                    }
                 }
   
            }
            else   //URLがあったら
            {



            }
        }
  
        private void buttonGethtml_Click(object sender, EventArgs e)
        {  //作成中
         }

        public Boolean keywordCheck()
        {
            Keyword = comboBoxKeyword.Text;

            if (Keyword == "")
            {
                if (MessageBox.Show("Kyeword is Blank is OK ?", "Notice", MessageBoxButtons.OKCancel) == DialogResult.OK)
                {
                    return true;
                }
                return false;
            }
            else
            {
                return true;
            }

        }

        public bool writeOutCheck()
        {
            if (checkBoxWriteOut.Checked == false && checkBoxPreview.Checked == false)
            {
                MessageBox.Show("Select output");
                return false;
            }
            else
            {
                return true;
            }
        }

        public void FileOpen()
        {

                DateTime dt = DateTime.Now;
                string date = dt.ToString("yyyy_MM_dd_HH_mm_ss");

                OpenFileDialog ofd = new OpenFileDialog();

                if (ofd.ShowDialog() == DialogResult.OK)

                {

                    ViewBoxBackColorSet();
                    textBoxPreview.AppendText(dt.ToString("HH:mm:ss" + Environment.NewLine));

                    //   string[] StrArryData = new string[3]; // 1行分のデータを格納する作業オブジェクト
                    using (var sr = new StreamReader(ofd.FileName))  //型はVariant
                    {
                        int lineCount = 0;
                        if (checkBoxWriteOut.Checked == true)
                        {
                            using (StreamWriter writer = new StreamWriter(date + ".txt", true))
                            {  //インデックス
                                writer.Write("Souce File Name = " + ofd.FileName + Environment.NewLine);
                                writer.Write("Keyword = " + Keyword + Environment.NewLine + "" + Environment.NewLine);
                                writer.Write("======================= " + Environment.NewLine + Environment.NewLine + Environment.NewLine);
                            }
                        }
                        var line = "";
                        while ((line = sr.ReadLine()) != null)      // ストリームの末尾まで繰り返す
                        {
                            int index_check = line.IndexOf(Keyword); //含まれてないときは"-1"
                            if (index_check > -1)
                            {
                                lineCount++;

                                if (checkBoxPreview.Checked == true)
                                {
                                    textBoxPreview.AppendText(line + Environment.NewLine); //追記モード
                                }
                                if (checkBoxWriteOut.Checked == true)
                                {
                                    using (StreamWriter writer = new StreamWriter(date + ".txt", true))
                                    {
                                        writer.Write(line);
                                        writer.Write(Environment.NewLine);
                                    }
                                }
                            }
                        }
                        labelLineCount.Text = lineCount.ToString();
                        ViewBoxBackColorReset();
                    }
                }
          }


        private void buttonClear_Click(object sender, EventArgs e)
        {
            textBoxPreview.ResetText();
            comboBoxKeyword.ResetText();
            textBoxPreview.ResetText();
            labelLineCount.Text = "0";
            textBoxURL.ResetText();
        }

        private void buttonKeywordOpen_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("notepad.exe", @"""ListKeyword.txt""");
        }


        public void ViewBoxBackColorSet()
        {
            textBoxPreview.BackColor = Color.FromArgb(0xdd, 0xdd, 0xdd);
            buttonGethtml.Enabled = false;
            buttonFileOpen.Enabled = false;
            buttonClear.Enabled = false;
            buttonKeywordOpen.Enabled = false;
        }
        public void ViewBoxBackColorReset()
        {
            textBoxPreview.BackColor = Color.White;
            buttonGethtml.Enabled = true;
            buttonFileOpen.Enabled = true;
            buttonClear.Enabled = true;
            buttonKeywordOpen.Enabled = true;
        }

        }

    }

}

C# で配列の要素を並べ替える

要素の中身を最近使ったものから順番に並べ替える。

private void Form1_Load でファイルのなかみを読み込み、ComboBoxにInput。
CombBoxとはTextBoxに複数の要素をDropDownListから選べるもの。
f:id:s51517765:20170429112231j:plain

Listの中身はStreamReaderでよみこむ。
StreamReaderは必ず、srKeyword.Close() で開放しておく。
そうしないと、今度書き込むときにErrorがでる。

private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) でアイテムが選択されたときに実行される。
要素の配列をひとつづつずらす。

            for (int n = 7 - 1; n >0 ; n--)
            {
                array_ex[n + 1] = array_ex[n]; //ひとつづつ配列のようそをずらして最新のものを[1]に入れる
              }

最後にファイルに書き込み記録。
ここでは、追記をfalseにして上書きする。
trueでは追記になって、実行されるたびに無駄に要素がふえてしまう。

StreamWriter sw = new StreamWriter("list.txt"<span style="color: #d32f2f">,false</span>, System.Text.Encoding.GetEncoding("shift_jis"))

本当は、重複要素のCheckとかしたい。


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;    //ファイルIO


namespace narabekae
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
         }

        string[] array_ex = new string[12];
        string[] array_temp = new string[12]; 

        private void Form1_Load(object sender, EventArgs e)
        {     //アプリ起動時に実行される
            int n = 1;
            var listKeyword = "";
            comboBox1.Items.Clear();  //コンボボックスの初期化
            StreamReader srKeyword = new StreamReader("list.txt");
            while ((listKeyword = srKeyword.ReadLine()) != null)
            {                                   
                if (listKeyword == null || listKeyword == "")  //要素の空欄はskip
                { }
                else { 
                    array_ex[n] = listKeyword;
                    comboBox1.Items.Add(listKeyword);
                    n++;
                }
              }
            srKeyword.Close(); //streamを閉じる
        }

        private void button1_Click(object sender, EventArgs e)
        {
               //要素を6つまで表示、必須ではない
                label1.Text = array_ex[1].ToString();
                label2.Text = array_ex[2].ToString();
                label3.Text = array_ex[3].ToString();
                label4.Text = array_ex[4].ToString();
                label5.Text = array_ex[5].ToString();
                label6.Text = array_ex[6].ToString();
            
        }

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {            //コンボボックスからItemが選択されたとき
            //値を取得
           string getItem = comboBox1.SelectedItem.ToString();
            label7.Text = getItem.ToString();
    
            for (int n = 7 - 1; n >0 ; n--)
            {
                array_ex[n + 1] = array_ex[n]; //ひとつづつ配列のようそをずらして最新のものを[1]に入れる
              }

            array_ex[1] = getItem;
            label1.Text = array_ex[1].ToString();
            label2.Text = array_ex[2].ToString();
            label3.Text = array_ex[3].ToString();
            label4.Text = array_ex[4].ToString();
            label5.Text = array_ex[5].ToString();
            label6.Text = array_ex[6].ToString();

            StreamWriter sw = new StreamWriter("list.txt",false, System.Text.Encoding.GetEncoding("shift_jis"));
            foreach (string eee in array_ex )
            {  //ファイルを更新
          
                sw.Write(eee + System.Environment.NewLine);
            }
            
            sw.Close(); //streamを閉じる
        }
     }
}

VC#でソフトウェア使用許諾のようなものを作る

自身が作ったプログラムを公開した時に、使った人が何らかのトラブルが起きてしまったら…。

そのプログラムが動かないだけならたいした問題ではないですが、ローカルのファイルにアクセスしたり、ネット上のデータにアクセスするときは取り返しのつかない状況を起こしてしまうことが起きえます。

たとえば、誤ったプログラムで、ローカルのユーザーのファイルを削除してしまったり…。

そのようなときに、一般にはソフトウェアの製作者は正しい方法であろうとなかろうと提供したソフトウェアの対価を超える補償はしません。

f:id:s51517765:20170415173411j:plain

このような画面は必ずと言っていいほどインストール時に出てくるか、Readmeなどの添付ファイルがあります。

簡易的に、補償しないことを受諾しないと使えない仕組みを作ってみました。
別の、本来の目的のためにプルダウンの中身を”ListKeyword.txt”に書き込む仕組みを作るので、ここに使用許諾の仕組みを追加します。

正しい方法でライセンスキーを入手しない限り、”OKCancel”がでてきて"OK"を押下しないと使えないようにします。

アプリケーションを起動したときに実行されるForm Loadに”ListKeyword.txt”をStreamReaderで読み込みComboBoxのItemに追加する本来の機能に、ライセンスを読み込ませます。

ここではライセンスキーは"123456789012"です。

 if (listKeyword != "123456789012")

”!=” は一致しないときを示す演算子です。
"123456789012"以外はComboBoxのItemに追加する本来の機能を動作させ、"123456789012"のときはelseでライセンスキーをSetします。

  UserSet == true

ここで、UserSetは"Boolean型"の変数です。
Boolean型はtrue or falseの2値をとる変数です。
有効・無効、あり・なし、ON・OFF などを入れるのに使います。
intで0 or 1とする方法を使う人も良く見かけますが、ただしくはBoolean型で定義するべきです。


ライセンスキーがないときは
OKCancelボタンをだします。

  if( MessageBox.Show("このソフトウェアを使用してのいかなる場合も製作者は補償いたしません。", "License confirmation", MessageBoxButtons.OKCancel) != DialogResult.OK)

これは、MessageBoxと選択ボタンを組み合わせたものにさらに、ifで判断を加えたものです。
ここでも"!="を使います。
ここで、”OK”を選択したときにソフトウェアのメイン画面に進み、”キャンセル”を選択したときに許可しない、と考えがちですがこれだとたとえば、右上の×をクリックしてどちらも選択しないと、メイン画面に進めるようになってしまいます。
f:id:s51517765:20170415180229j:plain

これはOK、Cancelと見せかけて実は、その他の選択ができてしまうということです。

あとは、OKが選択されなかったらアプリケーションを終了させるようにします。

close()

あとは、なぜ起動できないのかのメッセージをだしてあげれば親切でしょうか。

    private void Form1_Load(object sender, EventArgs e)
        {
            Boolean UserSet = false;
            var listKeyword = "";
            StreamReader srKeyword = new StreamReader("ListKeyword.txt");
            while ((listKeyword = srKeyword.ReadLine()) != null)      // ストリームの末尾まで繰り返す
            {
                if (listKeyword != "123456789012") //ライセンスキーでないときは本来の動き
                {
                    comboBoxKeyword.Items.Add(listKeyword);
                }
                else
                {
                    UserSet = true; //ライセンスキーがあったら
                }
            }
            
            if (UserSet == false)
            {
               if( MessageBox.Show("このソフトウェアを使用してのいかなる場合も製作者は補償いたしません。", "License confirmation", MessageBoxButtons.OKCancel) != DialogResult.OK)
                {
                    MessageBox.Show("使用許諾に合意しないと使用することはできません。");
                    Close();
                }
            } 
        }

C#でTextファイルへの入出力

例としてHearth Loggerを作ります。
Form1は以下のようなものを作りました。

仕様としては、
・入力は日付、体重、体脂肪率
・プログラムを起動したら、日付は今日の日付を表示。ただし、手入力で変更可能
・OKを押下でファイルに記録。
・OKを押したときグラフCheckboxがONならグラフを表示

f:id:s51517765:20170329203915j:plain


まず、ファイル入出力を扱うので、以下を追加します。

using System.IO;

OKボタンを押下したときに、日付、体重、体脂肪を「カンマ」区切りでtxtもしくはcsvに取り込みます。
日付は後述で自動的に今日の日付を入れるようにしてありますが、体重と体脂肪が空欄の時は追記をスキップします。
チェックボックスがCheckedのときは、グラフを表示します。
グラフの表示にCheckboxの判断を掛け合わせていますが、グラフのインスタンス生成のところはよくわかってないので適切かどうか…。

 private void button1_Click(object sender, EventArgs e)
        {
            double weight;
            double fat;
            if (double.TryParse(textBoxWeight.Text, out weight) == true &&
                double.TryParse(textBoxFat.Text, out fat)==true)
            {
                using (StreamWriter writer = new StreamWriter("data.txt", true)) 
                      //書き込む先のファイル名は"data.text"
                {
                    writer.Write(textboxDate.Text); //textboxの内容を書き込む
                    writer.Write(",");          //任意(ここではカンマ)のTextを書き込む。
                    writer.Write(textBoxWeight.Text);
                    writer.Write(",");
                    writer.WriteLine(textBoxFat.Text);
                    writer.Flush();
                    textBoxWeight.Text = "";  //入力欄であるtextboxをクリア
                    textBoxFat.Text = "";
                }
            }

            Graph Form2 = new Graph();   //グラフのインスタンス生成
            if (checkBoxGraph.Checked == true)  //Checkbox判断
            {
                if (Form2.ShowDialog() == DialogResult.OK) //OKボタンが押されたら
                {

                }
            }

            Form2.Dispose();

        }

日付は今日の日付を取得し、年月日の形式で表示します。

     private void Form1_Load(object sender, EventArgs e)
        {   //Form1が開いたときの動作
            DateTime dt = DateTime.Now; //dtに今日の日付(と現在時刻)
            textboxDate.Text = dt.ToString("yyyy-MM-dd");  //textboxに文字列として"dt"をyyyy-mm-ddの日付形式で
        }

ここまでが、Form1。

ここからForm2。
Form2が読み込まれたときの動作。
始めにまとめて変数を定義しています。
Tryの中でファイルを開いて、日付、体重、体脂肪率にわけて配列に読み込むようにしています。
ここで、Tryは処理に例外が発生した場合、CatchにすすみErrorを出します。
Try,Catchの構文で、予期せぬErrorで止まってしまうのを防ぎます。

   private void Form2_Load(object sender, EventArgs e)
        {
            int n = 1;
            int no = 0;
            int Data_Count=4;
            int Array_Length = 400;
            string[] date = new string[Array_Length];
            string[] Weight_text= new string[Array_Length];
            double[] Weight = new double[Array_Length];
            string[] Fat_text=new string[Array_Length];
            double[] Fat = new double[Array_Length];
            DateTime[] date_style = new DateTime[Array_Length];

try
            { //csvファイルを開いて、日付、体重、体脂肪率にわけて配列に読み込む

                string[] StrArryData = new string[3]; // 1行分のデータを格納する
                using (var sr = new System.IO.StreamReader(@"data.txt")) //読み込むファイル名
                {

                    while (!sr.EndOfStream) //ファイルエンドまで
                    {
                        var line = sr.ReadLine();    // ファイルから一行読み込む
                        StrArryData = line.Split(','); //一行を区切る

                        foreach (string value in StrArryData) //strArrayDatsをStringとして、そのすべてに対して
                        {

           //Data3つごとに分けて配列に格納
                            if (n % 3 == 1)
                            {
                                date[no] = value;
                                DateTime.TryParse(date[no], out date_style[no]); //textをDateTime型に
                            }
                            else if (n % 3 == 2)
                            {
                                Weight_text[no] = value;
                                double.TryParse(Weight_text[no], out Weight[no]); //Textを数値に型変換
                            }
                            else if (n % 3 == 0)
                            {
                                Fat_text[no] = value;
                                double.TryParse(Fat_text[no], out Fat[no]);
                                no++;
                            }
                            n++;
                        }
                        Data_Count = no;
                    }
                }
            }
           catch (System.Exception ee)
            {
                MessageBox.Show("Error");
                // ファイルを開くのに失敗したとき
            }

次に、グラフの表示内容

           // 1.Seriesの追加
            Chart1.Series.Clear();
            Chart1.Series.Add("Weight (kg)");
            Chart1.Series.Add("Body fat (%)");
            

            // 2.グラフのタイプの設定
              Chart1.Series["Weight (kg)"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
              Chart1.Series["Weight (kg)"].MarkerStyle = System.Windows.Forms.DataVisualization.Charting.MarkerStyle.Diamond;
              Chart1.Series["Body fat (%)"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
              Chart1.Series["Body fat (%)"].MarkerStyle = System.Windows.Forms.DataVisualization.Charting.MarkerStyle.Diamond;
          
            // 3.座標の入力
            for (no = 0; no < Data_Count; no++)
            {
                Chart1.Series["Weight (kg)"].Points.AddXY(date_style[no],Weight[no]);
                    Chart1.Series["Body fat (%)"].Points.AddXY(date_style[no], Fat[no]);
               }

グラフはこのページを参考にした…というより丸写しに近い。
whoopsidaisies.hatenablog.com

f:id:s51517765:20170329220510j:plain

Visual Studioで間違ってClickイベントができてしまったら

Visual StudioC#コーディング中、よく起きるのが、まちがってフォームクリックイベントを作ってしまうこと。

private void Label1_Click(object sender, EventArgs e)
{

}

これをだからといって、Codeから消そうとすると、DesignerがErrorを出す。
f:id:s51517765:20170323230004j:plain

正しい解法は↓

1.デザイン画面で、イベントハンドラを消したいコントロールを選択。
2.プロパティウインドウのイベント一覧ボタン(雷マーク)をクリック。
3.消したいイベント名(一覧左側のClickとか)を右クリック。
4.「リセット」を選択。

detail.chiebukuro.yahoo.co.jp

Visual Studioでフォームデザインが表示されないと思ったら

Visual StudioでVC#プログラミングをしているとき、何かの拍子にForm1.cs[デザイン]のタブがいなくなった。

f:id:s51517765:20170224213628j:plain

このように、Form1.csに対して、

f:id:s51517765:20170224213632j:plain
のようなもののことだが。

通常、プロジェクトファイルは、VS上で ファイル¥開く¥プロジェクト/ソリューションと 選択するか、
f:id:s51517765:20170224213859j:plain

直接エクスプローラから選択すると、通常は開発画面が復旧する。

しかし、Form1.cs[デザイン]がいなくなってしまった状態では、いない状態しか現れない。
エクスプローラからForm.csやForm1.Designer.csは開けるが、Form1.cs[デザイン]はない。
f:id:s51517765:20170224213905j:plain
かといって、プロジェクトが壊れてしまったとか、関連付けがなくなってしまったわけではないようで、Debug/Release機能を使えば正常にアプリが動作しているのである。

ぐぐるが似たようなキーワードの現象は見つかるものの、ちょっと違うようなのである。

www.google.co.jp

試行錯誤の結果、右側のソリューションエクスプローラから開くことができた。
Form1.cs をダブルクリック。
f:id:s51517765:20170224215342j:plain

うーん、やれやれ。

ちなみに↓は6章まで読み進めた。

ゴールからはじめるC# ~「作りたいもの」でプログラミングのきほんがわかる

ゴールからはじめるC# ~「作りたいもの」でプログラミングのきほんがわかる

オブジェクト思考、クラス、インスタンスといったところが分かりにくいが、すべてはわからなくても何とかなる。

Visual Studio 2015によるWindowsアプリケーション作成

Visual Studio Community 2015によるWindowsアプリケーション作成を始めました。

もともとはC言語によるプログラミングをやっていましたが、コマンドプロンプトで動作するプログラムだけではなく、Windowsアプリを作ってみようと思いました。

そこで、Visual Studioをつかえばそういったことができるとわかりました。
しかし、Visual StudioC言語はできなくはないけど、すでに推奨環境ではないことがわかりました。

ようするに、Windowsアプリをこれから始めようとするなら、 Visual C#または Visual Basicのほうが良いということです。

Visual Studio Communityでも標準インストールではC/C++はインストールされません。

Visual C#C#の拡張でWindowsアプリなどを作ることができるものですが、C#C/C++Java? の拡張らしいです。

ちょっと調べてみると、C#はCの類推だけでもかなり理解できそうだとわかりました。
しかも、文法の許容範囲が広く、むしろ簡単のようです。
(文法の制限が緩いということは、意図しない動作を許容することになるので必ずしもいいことだけではありませんが)

そんな感じで作ってみたのが
f:id:s51517765:20170205112053j:plain

開発画面はこんな感じ。
f:id:s51517765:20170205112101j:plainf:id:s51517765:20170205112710j:plain
金利計算は簡易的です)

参考にしたのは↓

コマンドプロンプトで動作するコンソールアプリケーションと言われるものとVisual C#のもっとも違う点は、
Formでのボタンクリックや、テキストボックスからの情報の取得です。
それ以外はこれまでに学んできたCの基本がそのまま使えます。


ボタンクリックで動作する内容は、Form画面で設置した”ボタン”をダブルクリックすると、このようなコードが自動生成します。
この中にコードを記述します。

  private void button1_Click(object sender, EventArgs e)
        {
      }

テキストボックスへの出力はこのような形。

label3.Text = year + "年で達成できます。";

この本には各章ごとに練習問題があり、この本を購入するとそのコード全文も見ることができます。
ですから、自分ではわからないことはどのように記述すればいいかも答えを見ることができます。

たとえば、4章の章末問題はこのようなもの。
f:id:s51517765:20170205120039j:plain

ゆっくり勉強しても2週間ぐらいでこれぐらいまでできるようになりました。

ちなみにこの本はKindle版もあるようですが、これに限りませんが視認性は紙に限りますね。