iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 4
2
Software Development

你會十五種程式語言?不,我會十五種HelloWorld.為了避免這種狀況,因此寫了這篇:淺入淺出十五種程式語言系列 第 4

C# 如同精靈般優雅且高貴 (上)

C#

寫在前面

這邊主要會提一下這個語言跟前言,如果沒興趣可以跳到這裡

原本猶豫第一個語言要介紹什麼,主要有三個前提

  1. 必須是強型別,先建立好型別觀念後寫弱型別可以避開很多陷阱
  2. 必須是編譯式的,才能夠在撰寫的同時排除掉奇怪的問題,也能夠介紹結構化的概念
  3. 必須簡單

第一點就把常見的新手語言 javascript 排除了
(也許我們永遠不會了解為什麼 2 + "2" = "22" 但是 2 x "2" =4, 參考)
第二點則排除了寫網站常用的 Ruby 跟 php ,還有現在超紅的python
第三點排除了學校常教的第一個語言 C/C++就被排除了,Rust 處理的東西很底層因此也被排除

剩下站在擂台上的選手剩下 java 跟 C#還有 GO
雖然私心想推薦 GO,但是相較 java 跟 C#,GO 不算是完整的物件導向語言,但是這又是很重要的概念,所以只能請 GO 下擂台
最後二選一中其實很猶豫,因為 java 在流行榜上霸佔第一已久,所以理應將他放在第一個介紹的語言
但是需要介紹轉譯的概念,所以最終還是選擇C#

注意這個順序並不代表排行,只是這樣介紹觀念比較順

接著

讓我們開始吧

這次要介紹的語言是 C#,不過我們不直接開始寫程式,首先要先安裝 dotnet core
不使用常見的 Visual Studio 配合 .NET Framework 的理由是因為有些人可能是使用 MAC 或 linux,
因此採用跨平台的 dotnet core
先去安裝吧,我會在這裡等你們

好了嗎?
那我們繼續,打開 VScode,點選左上角的檔案->開啟資料夾,開啟你想要放置專案的資料夾,
接著在終端機內輸入下面的指令(忘記如何使用終端機? 按下你的 ctrl + ~)

dotnet new console -n convert

接著你會看到當前所在的資料夾會出現一個名叫 convert 的資料夾,裡面有這些

https://ithelp.ithome.com.tw/upload/images/20200904/20127836UZOYRld4Md.png

這些都是 dotnet core 自動幫你產生的,不過我們目前只需要關心 Program.cs 這個檔案
請在 VScode 裡面打開它
接著你會看到

https://ithelp.ithome.com.tw/upload/images/20200904/20127836SS1kXWGtZv.png

在終端機使用cd將目錄切換到跟Program.cs同級的位置

執行

dotnet run

就可以看到你的程式跑起來拉

這個是最簡單的 C#結構
在 namespace 內有個 class,class 內有個 function,function 內有行程式碼
接著我逐個介紹他們的含意

namespace

這是在 C#內最大的結構體,其目的是為了要組織好幾個 class
通常在非常大型的專案中才會看到其他的 namespace,因此這裡我們先不介紹它,有興趣的人可以前往這裡

其實第一行的 System 就是系統內建的其中一個 namespace,注意到下面這一行

Console.WriteLine("Hello World!");

這一行其實是

System.Console.WriteLine("Hello, World!");

不過由於在程式一開始已經有將 System 給 using 進來

using System;

因此可以省略 System

class

這個是整個 C#甚至是程式語言內最重要的概念

物件

記住這個名字,之後會專門介紹這個議題,我們先稍微提一下概念

物件裡面會包裹著各種各種屬性跟方法(我知道很多人都稱其為函式,但是當初我們大學教授就叫方法)
如果你現在還聽不懂也沒關係,之後會提到

class Program

就是定義了一個名叫 Program 的 class
裡面包裝了一個

方法

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

只要是編譯式的語言都會有一個程式進入點 (之後會專門介紹編譯與直譯的差異)
而 C#就是屬於編譯式的語言,所以他會有一個程式進入點

這個點就是 Main()

程式一旦開始執行就會去尋找名稱叫做 Main 的方法,並且當作是整個程式的起點

目前Main方法的內容為

Console.WriteLine("Hello World!");

這行程式將會在你的終端機內印出 Hello World
你可以把內容換成各種你想要的字(記得保留左右的"")並且再次執行

dotnet run

應該就會看到你剛才輸入的文字

好,接著我們要開始寫程式了

把你的 Main 程式換成以下的樣子

記得每一行結尾都要有; 這是 C#的規定

static void Main(string[] args)
{
    Console.WriteLine("Tell me what you want to do:");
    Console.WriteLine("(1)T to H (2)H to T");
    String choose = Console.ReadLine();
    Console.WriteLine(choose);
}

現在我們多了一個新東西

String choose = Console.ReadLine();

這行的用意在讀取你的輸入值,並且丟入一個叫 choose 的變數中

https://ithelp.ithome.com.tw/upload/images/20200904/20127836xdnsxUMNr6.png

並且在下一行

Console.WriteLine(choose);

中將 choose 印出來

等等,什麼是變數?

變數就是一個將值暫時存放的位置,可以在之後將這個位置叫出來使用

那什麼是型別?

所謂的型別就是變數的形式,在程式裡面數字的 1 跟文字的 "1" 是不相同的
所以為了區分數字跟文字,我們會把文字用兩個"給包起來
這也是為什麼我們要印出文字時會需要在印出的字左右側加上"

Console.WriteLine("Tell me what you want to do:");

我們一般將被左右"給包起來的文字稱為字串(String)

為什麼要區分型別呢?

理由在於每種型別我們對他做的事情不一樣
比方說如果型別是數字,那麼 1+1 就會是 2
但是如果你在打電話時連按兩個 1,你不會希望手機上顯示是 2 而是希望他顯示 11 對吧
所以"1"+"1"就會是"11"
我們之後會對型別深入探討,現在你只需要知道數字跟字串的型別不一樣即可

現在你可以使用 dotnet run 來執行你的程式了

這時你的終端機應該會出現

Tell me what you want to do:
(1)T to H (2)H to T

這時你隨便輸入一個字並且按下 enter,應該就會馬上印出你輸入的字

Tell me what you want to do:
(1)T to H (2)H to T
1
1

這就是一個最簡單會對使用者的輸入產生反應的程式了

現在我們需要對使用者的行為進行分類
當輸入 1 的時候幫使用者把十進位轉成十六進位,而當輸入 2 的時候把十六進位轉成十進位
這時我們可以使用 switch
現在修改你的程式碼如下

Console.WriteLine("Tell me what you want to do:");
Console.WriteLine("(1)T to H (2)H to T");
String choose = Console.ReadLine();
switch (choose)
{
    case "1":
        Console.WriteLine("Your input is 1");
        break;
    case "2":
        Console.WriteLine("Your input is 2");
        break;
    default: //Input is neither 1 nor 2
        Console.WriteLine("Wrong selection");
        break;
}

switch 就如同鐵路驗票員,他會告訴你在哪裡下車
告訴()你要前往的站名後,當火車開過各種 case 時,就會自動在符合的名下車

https://ithelp.ithome.com.tw/upload/images/20200904/20127836MKmfVlPHUc.png

現在,執行你的程式,並且隨便輸入,看會有什麼結果

等等! 程式碼有一部分你沒有提到!

你是說

//Input is neither 1 nor 2

嗎?

這個稱之為註解,在 C#內的註解符號是//
在此行中的//後面皆是註解,不會被程式碼所執行
因為當程式碼越來越多時,你需要專注於程式碼所產生的效果而不是程式碼本身,
所以我們需要註解提醒我們這行程式碼在做什麼
如果你需要跨行的註解時可以使用/**/

switch (choose)
{
    case "1":
        Console.WriteLine("Your input is 1");
        /*
            我們都是註解喔
            我們都是註解喔
            我們都是註解喔
        */
        break;
    case "2":
        Console.WriteLine("Your input is 2");
        /*
            Console.WriteLine("我們不會被印出來喔");
            Console.WriteLine("我們不會被印出來喔");
            Console.WriteLine("我們不會被印出來喔");
        */
        break;
    default:
        /*
            我們都是註解喔
            我們都是註解喔
            我們都是註解喔
        */
        Console.WriteLine("Wrong selection");
        break;
}

執行看看,你會發現註解中的程式不會被執行

好,我現在下車了,該去哪裡?

我們先來實做使用者輸入"1"時我們需要做的事吧

當使用者輸入"1"時程式已經知道使用者想將十進位轉成十六進位了,那你現在需要知道他想轉換什麼數字
所以再次請使用者輸入,並且讀取他的輸入,然後輸出到螢幕上
工具你已經都有了,先去實做看看再回來對答案吧

好了嗎? 往下看答案吧

case "1":
    Console.WriteLine("Please enter the number:"); //當然,這邊你可以打中文或任何你想提示使用者的文字,但是記得用""包起來
    String number = Console.ReadLine();
    Console.WriteLine(number);
    break;
case "2":
    Console.WriteLine("Your input is 2");
    break;
default:
    Console.WriteLine("Wrong selection");
    break;

接著我們來實做計算的部份吧,還記得怎麼將十進位轉成十六進位嗎?
我們需要知道十進位的數字是由幾個 16 的各種次方組成的

https://ithelp.ithome.com.tw/upload/images/20200904/20127836HtPMDOsUvq.png

先修改你的程式碼如下

case "1":
    Console.WriteLine("Please enter the number:");
    String number = Console.ReadLine();
    Int64 num = Int64.Parse(number);
    for (int i = 0; i < 16; i++)
    {
        for (int j = 0; j < 16; j++)
        {
            for (int k = 0; k < 16; k++)
            {
                Console.WriteLine("{0}{1}{2}",i,j,k);
            }
        }
    }
    break;
case "2":

怎麼一下突然多了好多東西!?

別擔心,讓我一個一個介紹

首先是

Int64 num = Int64.Parse(number);

因為從終端機讀取到的輸入會是字串,但是我們需要他是數字,否則無法進行計算
所以這一行的目的就是為了要轉型
將原本的型別轉型成另外一種型別,並且給他一個變數名稱
在這裡轉型的目標型別是 Int64,目標變數則是 num
Int64 是數字型態的一種,之後會在專門介紹型別的時候告訴你數字的型別到底有幾種,現在先記這一種就好
其實在 C#也可以寫成這樣

var num = Int64.Parse(number);

var 是隱含型別

合理的使用情況下,他會自動幫你判斷這個變數是什麼型別
由於我們已經在

Int64.Parse(number);

明確的告訴他我們要轉型成 Int64 了,因此實在沒有必要在宣告類型時在告訴他變數的型別是 Int64
這時候就可以使用 var 節省(工程師們)判斷與思考的時間

接著是

for (int i = 0; i < 16; i++)

他是一個迴圈,在符合條件的情況下,他會不斷的重複範圍內的程式碼
以下是條件的形式

https://ithelp.ithome.com.tw/upload/images/20200904/201278365kYqXZlMgY.png

什麼是 i++?

i++就是 i+1 的意思,
在這裡的用意是說每次迴圈執行完就會對 i+1,一直到 i不小於16(也就是等於或大於)
所以這個迴圈就會從 i=0 一直執行到 i=15,總共執行 16 次

那麼,迴圈執行的範圍是多大呢?

https://ithelp.ithome.com.tw/upload/images/20200904/20127836JuuxaKzqSy.png

{ }必須兩個一組來看,中間就是迴圈的範圍

Console.WriteLine 我認識,但是裡面怎麼多了個怪怪的東西?

{0}

這個是複合格式字串,裡面的數字代表會引用後面第幾個位置的輸入值

https://ithelp.ithome.com.tw/upload/images/20200904/20127836SHjefephRO.png

執行看看吧,看看迴圈是怎麼顯示的

輸入完 1(選擇進位轉換)跟隨便一個數字(要轉換的數值,不過我們目前不會處理他)後你應該會看到跑出一堆文字

.
.
.
151414
151415
15150
15151
15152
15153
15154
15155
15156
15157
15158
15159
151510
151511
151512
151513
151514
151515

有看出規則嗎?
k 是循環最快的,再來是 j 跟 i(跟時針分針秒針的模式類似)
理由是因為 k 是最內層的迴圈,一定會先將他輪完,才到 j 的下一個迴圈

你可以嘗試調整 i j k 的循環圈數來觀察迴圈的改變

再稍微修改你的程式碼,現在我們要來跟使用者輸入的數值互動了

for (int i = 0; i < 16; i++)
{
    for (int j = 0; j < 16; j++)
    {
        for (int k = 0; k < 16; k++)
        {
            if (Math.Pow(16,2)*i+Math.Pow(16,1)*j+Math.Pow(16,0)*k == num)
            {
                Console.WriteLine("{0} {1} {2}",i,j,k);
            }
        }
    }
}

現在注意看到這裡

if (Math.Pow(16,2)*i+Math.Pow(16,1)*j+Math.Pow(16,0)*k == num)

if

這是判斷語句,如果在()內的條件成立,將會執行{}內的程式(也就是 Console.WriteLine)

==

這是條件語句,將會決定條件是否成立

大致上結構如下

https://ithelp.ithome.com.tw/upload/images/20200904/20127836s8J8rhvv8P.png

類似的條件語句還有

> //大於
< //小於
!= //與==相反,左右側不同時才成立

讓我們回到我們的程式吧
==右邊的 num 我們已經知道了,也就是將使用者輸入所轉成的數字
而左側有一大段程式碼,讓我們繼續拆解下去
有注意到兩個+嗎?
我們靠著+將左側的語句繼續細分,你可以看到下列的結構

Math.Pow(16,2)*i

好,還記得嗎?這裡的 i 就是我們在迴圈內定義過的 i

for (int i = 0; i < 16; i++)

如果忘記了往上翻一下再回來

中間的*則是乘號

Math.Pow(16,2)

這個是次方計算,前面是底數,後面則是指數
所以這串運算的結果就是 16^2

理解了各部份之後我們現在將他們組裝起來

https://ithelp.ithome.com.tw/upload/images/20200904/20127836Vrjfp0iEbN.png

因此迴圈會在三個 0~15 內循環,如果找到跟使用者輸入的數值相同的計算結果便會印出來
現在運行你的程式,並且在第二段輸入的時候輸入 0~4095 之間的數值
(要不要想想看為什麼最大值是 4095)

https://ithelp.ithome.com.tw/upload/images/20200904/20127836eTrwK8zyDE.png

如果你輸入的數值是 4095 應該會看到上圖的輸出
會出現三個 15 的理由是因為 16^2x15+16^1x15+16^0x15=4095
這個數值也剛好是長度為 3 的十六進位最大值,因為再加 1 的話就會進位成 1000 了

不過十六進位的數字不是0~F嗎?

沒錯,因此我們需要轉換
明天我們繼續往下寫轉換的方法


上一篇
16 進制與 10 進制
下一篇
C# 如同精靈般優雅且高貴(下)
系列文
你會十五種程式語言?不,我會十五種HelloWorld.為了避免這種狀況,因此寫了這篇:淺入淺出十五種程式語言30

1 則留言

0
skycover
iT邦新手 5 級 ‧ 2020-09-04 23:09:03

如果有任何寫不清楚或是觀念沒有很明白的話請留言告知我
會盡快補上

如果有任何寫錯的地方也麻煩留言告知我
會盡快修正

感謝各位

我要留言

立即登入留言