23
22

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

長野高専Advent Calendar 2023

Day 20

学校では教えてくれないC#のおはなし

Last updated at Posted at 2023-12-19

はじめに

この記事は長野高専 Advent Calendar 2023の20日目の記事です。
3年連続 @shun-shobon さんが主催されています。今年もありがとうございます!
惜しくも3年連続12/21の記事とはなりませんでした(去年一昨年)。

本記事では、業務で半年ほどC#を使った私が感じたC#の特徴・強みを、浅い知識と経験ながら述べたいと思います。
C#のプロから見れば稚拙な記事かと思いますが、C#に手を出したい人やC#のWindows GUI/Web アプリケーションに興味がある方が一歩目を踏み出すきっかけになればと思います。

「学校では教えてくれない」とありますが、ほとんど教えてくれます。

お前誰だよ

長野高専は卒業してしまっているので、軽く自己紹介をします

HN        :K_White
所属(高専時代):長野工業高等専門学校 電子情報工学科 18s
所属(現在)  :BtoB企業 開発部
やってること  :SaaS製品の開発・保守
好きなもの   :音楽(HARDCORE TANO*C、星街すいせい)、V(ホロ、にじ、ぶいすぽ)、ゲーム(APEX、OW、NieR...)

C#とは

この章は学校で教えてくれる内容だと思います

以下、Wikipediaからの引用

C#(シーシャープ)は、マイクロソフトが開発した、汎用のマルチパラダイムプログラミング言語である。C#は、Javaに似た構文を持ち、C++に比べて扱いやすく、プログラムの記述量も少なくて済む。また、C#は、.NET Framework上で動作することを前提として開発された言語であり、WindowsアプリケーションやWebアプリケーションの開発に適している。
マルチパラダイムをサポートする汎用高レベルプログラミング言語で、静的型付け、タイプセーフ、スコープ、命令型、宣言型、関数型、汎用型、オブジェクト指向(クラスベース)、コンポーネント指向のプログラミング分野を含んでいる。

大体あってると思います(最悪)

C++に比べて扱いやすいかはさておき、オブジェクト指向を基本としたJavaライクな構文のため、文法に対して抵抗なく使える人が多いと思います。また、.NET Framework(.NET Core/n) のおかげでプラットフォームを気にせず開発ができます。
大抵はWindowsアプリケーション開発に使用されますが、Unityでゲーム開発をする際の言語としても使用されます。

HelloWorld.cs
public class Hello{
    public static void Main(){
        System.Console.WriteLine("Hello World!");
    }
}

// 出力結果
//
// Hello World!

.NET Framework(.NET Core)とは?

.NET Framework(.NET Core)とは、Microsoft社が提供するソフトウェアフレームワーク及びランタイム環境のことです。

C#は基本的には.NET環境上で動かします。そのためC#と.NETは切っても切れない関係です。
C#を使う上での基礎知識として、.NETとは何たるか、を頭の片隅に置いておくのが良いでしょう。

.NET Coreは簡単に言えば「.NET Frameworkの上位互換」です(おや)。使用感は.NET Frameworkとほぼ変わらず、クロスプラットフォームに対応したのとクラウド運用方面を強めた感じになっています。
ちなみに最近は.NET Frameworkから .NET Core に移行する流れがほとんどです。新しいプロジェクトはほぼほぼ.NET Coreでやってる印象です。逆にレガシーなソフトウェアの保守などはまだまだ.NET Frameworkを使っています。

.NET 5以降は.NET Frameworkと.NET Coreを統合する動きがみられて、.NET 6からは区別しないリリース(つまり実質統合)が始まりました。
そのため 「.NET」と言えば「.NET Core」の機能を指すことが多い です。

.NETはCLR(Common Language Runtime)を搭載しています。そのため、ある程度好きな言語で開発が可能で、デプロイ先を気にせずにアプリケーションを開発できます。

何に使うの?

活用例は調べれば山ほど出てくると思うので、主に使われている事例を簡単に3つ紹介します

1. Windowsアプリケーション

前述したように、主にWindowsアプリケーション開発に用いられます。GUIにこだわらず、広い種類のアプリケーションが作成できます。MSが関わる多くのサービスはC#で開発されているでしょう(偏見)。

2. Webアプリケーション

最近は専らWebアプリケーションの流れですが、C#でもWebアプリケーションが開発できます。
アプリケーションのビルドには「ASP.NET」というフレームワークを使用します。

本記事の流れに合わせて簡単に言えば、「C#のアプリケーションをWebにするためのもの」です。バックエンドは今まで通りC#で作り、出力だけWebブラウザにするだけです。簡単ですね!

ASP.NETで提供されるフレームワーク

WebPage
単純なHTMLマークアップ(C#を埋め込んでサーバとやりとり)
MVC
MVCモデルでの開発を手助け
WebForms
ドラッグアンドドロップだけでWebページとそのコントローラを構成

おすすめはASP.NET MVCです。SPA(Single Page Application)が流行っているのでMVCモデルはうってつけでしょう。
WebFormsは一見楽そうですが、1からの開発となるとどうしてもコードが欲しくなる場面が多いので、既存のシステムが無い場合はあまりお勧めしません。

こちらもCoreへの移行が進んでいます。体感としてはデスクトップアプリケーション分野よりもこちらの方が移行が進んでいるように感じます。
ASP.NET Coreで提供されるフレームワーク

Razor Pages
WebViewとWebClassを1対1に対応させ、ページを起点に考えるマークアップ
MVC
ASP.NETの上位互換

3. ゲーム開発

ゲーム開発としてのC#はかなり有名だと思います。

Unity自体がC#で開発されており、ゲーム開発時に使用する言語もC#です。ステータスやデータを保存する、オブジェクトをクラスで管理する、などの用途には、C#はかなり適していると思います。

余談 - ゲーム開発例

一昨年の工嶺祭展示用に製作したゲーム「BLinDISM」はUnityを使用して製作されています。
開発後記はこちらです。


補足 - 有名なサービスの例

  • Stack Overflow
  • Microsoft Bing
  • MSN(Microsoft Network)
  • Unity

ここがつよいぞC#

半年ほど業務でC#を触り、高専で学習したCやJavaと比較して「いいじゃん」と思った点を2点(ほぼ1点)紹介します。

LINQ

C#を触って一番感動した機能が LINQ(Language INtegrated Query、統合言語クエリ) です。

クエリと聞くとDBやデータセットを対象とした処理と思う方が多いかと思います。
しかし、LINQの処理対象は「任意のIEnumerable(IEnumerable<T>)」コレクションなのです!
IEnumerableを継承しているオブジェクトはすべてLINQでの処理が可能なため、データ抽出・取得やソートなどが格段に楽になります。また、コード量も削減され、可読性が高まります。

C#を使用する人のほとんどがLINQの恩恵を受けられるでしょう。C#でコーディングをするなら、LINQを使わない手はありません。

LINQの構文には「クエリ構文」と「メソッド構文」の2つがあります。

クエリ構文
SQLのような記述方法
メソッド構文
メソッドチェーンで記述する方法

どちらも機能としてはほぼ変わりません。(メソッド構文にある処理がクエリ構文に用意されていない場合などはある)
どちらを選ぶかは各人の好みやコーディング規約によりますが、IEnumerableコレクションが処理中に出てくることと個人的に見やすいという理由で、自分は圧倒的にメソッド構文を推しています。

// クエリ構文
var userName = from user in users
                where user.Age >= 30
                select user.Name;

// メソッド構文
var userName = Users.Where(x => x.Age >= 30)
                    .Select(x => x.Name);

LINQの例として、ユーザ情報を保持しているデータクラスを処理する場合を見てみましょう。
以下のようなデータクラスを定義します。

User.cs
public class User {
    public int Id { get; set; }
    public string Code { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    public Gender Gender { get; set; }
    public Dest Dest { get; set; }
    public class AttendInfo {
    public DateTime EntryTime { get; set; }
    public DateTime ExitTime { get; set; }
}

public enum Gender {
    Man = 1,
    Women = 2,
    Others = 3
}

public enum Dest {
    Dev = 1,
    Sales = 2,
    Consulting = 3,
    General = 4,
    Financial = 5
}

例1. 複雑な抽出

条件

  • 年齢…30歳以上
  • 性別…男性
  • 所属…開発かコンサル
  • 退勤時刻…2023年11月29日 18:00以前

LINQを使用しない処理

Main.cs
// データマスタ
List<User> Users = new List<User>();

//
// Usersにデータを読み込む
//

// データ取得
List<User> queryUser = new List<User>();
foreach (var user in Users) {
    if(user.Age >= 30
        && user.Gender == Gender.Man
        && (user.Dest == Dest.Dev || user.Dest == Dest.Consulting)
        && user.ExitTime <= new DateTime(2023, 11, 29, 18, 0, 0)) {
        queryUser.Add(user);
    }
}

LINQを使用する処理

Main.cs
// データマスタ
List<User> Users = new List<User>();

//
// Usersにデータを読み込む
//

// データ取得
var queryUser = Users.Where(x => x.Age >= 30
                                && x.Gender == Gender.Man
                                && (x.Dest == Dest.Dev || x.Dest == Dest.Consulting)
                                && x.ExitTime <= new DateTime(2023, 11, 29, 18, 0, 0));

抽出のみの場合は条件式の量はあまり変わりません。注目すべきは条件以外の準備部分です。
データ取得時にいちいちforeachを書いて、ifで絞り込んで、ListAddする...煩雑極まりないですね。
LINQを使えば一発でIEnumerableコレクションが手に入ります。これは良い!

例2. より面倒な抽出と選択

条件

  • 年齢…30歳以上
  • 性別…男性
  • 所属…開発かコンサル
  • 退勤時刻…2023年11月29日 18:00以前

選択

  • CODE
  • 名前
  • 所属

選択条件

  • Idが一番若いデータ1件のみ

LINQを使用しない処理

Main.cs
// データマスタ
List<User> Users = new List<User>();

//
// Usersにデータを読み込む
//

// データ取得
object queryUser = null;
foreach (var user in Users) {
    if (user.Age >= 30
        && user.Gender == Gender.Man
        && (user.Dest == Dest.Dev || user.Dest == Dest.Consulting)
        && user.ExitTime <= new DateTime(2023, 11, 29, 18, 0, 0)) {
        if (queryUser == null || user.Id < queryUser.Id) {
            queryUser = new { user.Code, user.Name, user.Dest };
        }
    }
}

LINQを使用する処理

Main.cs
// データマスタ
List<User> Users = new List<User>();

//
// Usersにデータを読み込む
//

// データ取得
var queryUser = Users.Where(x => x.Age >= 30
                                && x.Gender == Gender.Man
                                && (x.Dest == Dest.Dev || x.Dest == Dest.Consulting)
                                && x.ExitTime <= new DateTime(2023, 11, 29, 18, 0, 0))
                        .OrderBy(x => x.Id)
                        .Select(x => new { x.Code, x.Name, x.Dest })
                        .FirstOrDefault();

先ほどの抽出条件に選択条件を追加しました。
可読性の違いが一目瞭然ですね。メソッド構文を使用したコードは、個人的にはとてもすっきり見えます。

C、Javaと比較してデータ操作が簡単なのと、データ操作処理が簡単かつ簡潔に記述できるという点で、LINQはとても気に入っています。保守性の観点からも、読みやすいコードであることは重要なため、業務でデータを処理するタイミングのほぼ全てでLINQを使用するようにしています。
冒頭と同じことを述べますが、C#でのコーディングではほぼ確実にLINQの恩恵を受けられます。foreachifをゴリゴリ削減し、LINQを使って気持ち良くなりましょう!

癖のない記法

前述したように、C#はJavaライクなクラスベースの構文のため、言語がいくつか使える(Javaが書ける)という方にとってはかなり親しみやすい記法かと思います。

ChatGPT 3.5くんにいくつか特徴を聞いてみたので、その中から自分もいいと思った点を抜粋します(手抜き)。細かい説明は調べてください。

プロパティ

C#はプロパティを標準サポートしています。Javaのようにゲッター・セッターメソッドを定義する必要がないため、コードが簡潔になります。

MyClass.cs
public class MyClass
{
    public string MyProperty{ get; set; }
}
MyClass.java
public class MyClass
{
    private String myField;

    public String getMyField() {
        return myField;
    }

    public void setMyField(String myField) {
        this.myField = myField;
    }
}

デリゲートとラムダ式

C#は関数型プログラミングに必要なデリゲートとラムダ式も標準サポートしています。デリゲートによりメソッド内部での処理に自由度を持たせられたり、よりコンパクトで可読性の高いコードを書くことができます。

LINQよりは感動は薄かったですが、デリゲートによる恩恵はバリバリ受けているのでこれらも好きです。
(そもそもLINQの使用にはデリゲートとラムダ式が前提としてあるので)

// int…加算する値その1
// int…加算する値その2
// int…評価値(返り値)
Func<int, int, int> add = (a, b) => a + b;

// 使用例
int sum = CalculationUtil(12345, 67890, add);

Nullable型

C# 2.0から、任意の型にnullを許容するNullable型をサポートします。(組み込み参照型のstringはC# 1.1以前でもnullが入る)
また、C# 7.3以前の参照型はnull非許容にすることができませんでしたが、C# 8.0からnull許容/非許容を区別できるようになりました。これにより参照型でもより細かな扱いができるようになります。

設計思想にもよりますが、null許容としておくとチェック時に少し楽になります。
intでもstringでもdecimalでもbyteでも char!?!? でも、「その変数になにもしていない」ことを判定するときに初期値を気にする必要は無くなります。宣言時にnullとしてしまえば、チェック箇所ではどんな型もnullかどうかを判定するだけでよいのです。

些細な違いですが、「変数に操作がされていない」もしくは「所定の処理の結果、予期せぬ結果となった」場合に値を気にする必要がなく、単純にnullチェックすればよいだけ、という設計にできるのはかなり嬉しいです。余計な考えをしなくて済みます。

int? nullableInt = null;
int notNullInt = null        // ←Warning

string? nullableString = null;
string notNullString = null        // ←Warning

char? nullableChar = null;
char notNullChar = null;        // ←Warning

// 各種処理
if (nullableInt is null) {
    // 何かしらの処理
}

if (nullableString is not null) {
    // 何かしらの処理
}

// 処理は続く...

注意すべき点としては、Nullableを導入する場合、扱う変数の状態がnullなのか、初期値なのか、別の値なのか、を気にしながら実装する必要があります。

string hoge = "";
string fuga = "";
string? nFuga = null;

// 既存の「何もしていない」チェック
if(hoge == "" && fuga == "") {
    // 何かしらの処理
}

// Nullableを導入した場合のチェック
if(hoge == "" && nFuga is null){
    // 何かしらの処理
}

null許容/非許容 参照型はC# 8.0から、is nullis not nullC# 9.0からサポートされている構文です。
(2023年12月17日時点では、C#の最新バージョンはC# 12.0でした)

大抵の環境では新しめのC#を使っているかと思いますが、稀にC# 7.0とかを使っている環境もあったりするので、手元の環境に合わせて処理を変えましょう。

まとめ

いかがでしたか!

ゲーム制作のために個人的にC#を勉強し始め、就活の武器にしてみたりして、何だかんだでC#で仕事をしていますが、今のところは使いやすくてとても気に入っています。
Web系ほど大きな需要はないかも知れませんが、ゲーム開発やWindowsアプリケーション開発など、まだまだ求められる場面は多い言語だと感じます。

稚拙な記事ではありましたが、最後までご覧いただきありがとうございました。

地固めされていてドキュメントも多い、今後数年は需要があるだろうC#、やってみませんか?

23
22
18

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
22

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?