C/C++でいうところのconstをC#で。

C/C++から、初めてC#を触れたとき、最初に戸惑ったのが `const` キーワードです。

ここではC#の `const` キーワードではない、C++が持つ `const` キーワードの特性を振り返りつつ、それをC#でどのように実現しコードを安全にできるかということです。
C/C++の `const` キーワードは非常に強力なツールなので、C/C++で出来るセキュアな使い方が、C#の `const` キーワードどこまで実現できるかの挑戦です。

<!-- vim-markdown-toc GFM -->

* [ここで得られるもの](#ここで得られるもの)
* [本日のレシピ](#本日のレシピ)
* [C++のconstを振り返ってみよう](#cのconstを振り返ってみよう)
* [C/C++のconstキーワードをもう少し掘り進めてみる](#ccのconstキーワードをもう少し掘り進めてみる)
* [C#で再現してみる](#cで再現してみる)

<!-- vim-markdown-toc -->

## ここで得られるもの

* ちょっぴりセキュアなコーディングテクニック


## 本日のレシピ

* C++のconstを振り返る
* C#でC++のconstを何処まで再現できるか

## C++のconstを振り返ってみよう

C++において `const` は値が変更されないことを示すために使用しています。

これだけ聞くとC#も同じでしょ？ってなりそうなので少しC++の `const` をみていきましょう。

1. `const` 変数の宣言と使用
    ```cpp
    const int x = 10;
    x = 20; // ERROR: const 変数は変更不可
    ```
2. `const` ポインタの宣言と使用
    ```cpp
    int a = 10;
    const int* p = &a;
    *p = 20;  // ERROR: constポインタを通じての書き換え不可
    a = 20;   // 参照元の変数は書き換え可能
    ```
3. `const` ポインタ自身の変更不可
    ```cpp
    int a = 10;
    int b = 20;
    const int* p = &a;
    p = &b; // ERROR: constポインタ自身は変更不可
    ```
4. `const` 参照の宣言と使用
    ```cpp
    void print(const int& x) {
      x = 20;  // ERROR: const参照を通じての書き換え不可
    }
    int main() {
      int a = 10;
      print(a);
      return 0;
    }
    ```
5. `const` メンバ関数の宣言と使用
    ```cpp
    class MyClass {
     public:
      void func() {
        cout << "func() が呼び出されました" << end1;
      }
      void func() const {
        cout << "const func() が呼び出されました" << end1;
      }
    };

    int main() {
      MyClass obj1;
      const MyClass obj2;
      obj1.func();  // func() has been called
      obj2.func();  // const func() has been called
      return 0;
    }
    ```

以上がC/C++における `const` の主な役割で、安全に値やクラスを渡す事が可能となっています。

## C/C++のconstキーワードをもう少し掘り進めてみる

以下のマネー操作をする **Money** クラスがあるとき
```cpp
class Money {
 public:
  void addMoney(int money) {
    _moeny += money;
  }
  void useMoney(int money) {
    _moeny -= money;
  }
  int money() cosnt {
    return _money;
  }
 private:
  int _money;
};
```

以下のように引数に渡した **c** を内部で変更することができてしまいます。
```
int IsEmpty(Money$ money) {
  money.useMoney(10);
  return money.money() <= 0 ? 1 : 0;
}
```

これを変更したくない場合C/C++では `const` を加えるだけです
```
Money IsEmpty(const Money$ money) {
  money.useMoney(10); // ERROR: constキーワードのついていない関数呼び出しは不可
  return money.money() <= 0 ? 1 : 0;
}
```

もう少しパターンを見てみましょう

先程のマネーを財布が所持していたとき、そのマネーを呼び出し元が変更できないようにしたいときは以下のように戻り値に `const` を付けて返せば良いだけです。
```
class Wallet {
 public:
  const Money& getMoney() {
    return _money;
  }
 private:
  Money _money;
};
```
returnタイプに `const` を付けるだけでPalletクラスはマネーを変更される心配をする必要なく操作させることができます。
```
const Money$ money = player.getMoney();
money.setMoney(0, 0, 0, 0); // ERROR: constキーワード付き変数のためコンパイルエラー
```

しかし残念なことにC#ではこういった `const` は存在しませんでした。定数定義に対してのみ `const` を使用することが可能です。

## C#で再現してみる

先程のMoneyとWalletの関係性を参考にC#でWalletの持つMoneyを操作可能なものと、操作不可なものとをインターフェイスを利用して設計してみます。

まずWalletからMoneyの取得だけを取り出した **IReadOnlyWallet** を作成します
```csharp
interface IReadOnlyWallet {
  int Money { get; }
}
```
次に **IWallet** は **IReadOnlyWallet** を継承したMoneyを設定可能なインターフェイスを定義します
```csharp
interface IWallet : IReadOnlyWallet {
  int Money { set; }
}
```
最後にそれらの実態クラスを実装します
```csharp
class Wallet : IWallet {
  public Money Money { get; set; }
}
```

これらを利用すれば
```csharp
void OutputConsole(IReadOnlyWallet wallet) {
  Debug.Log($"Has {wallet.Money}.");
}
```
というように **get** にのみアクセス可能になります。

戻り値の場合も同様
```csharp
class Bank {
  private Wallet[] _wallets;

  public IReadOnlyWallet FirstWallet {
    get => _wallets[0];
  }
}

void Func() {
  var bank = new Bank()
  var wallet = bank.FirstWallet;
  wallet.Money = 100; // ERROR: コンパイルエラー
}
```
と、 **IReadOnlyWallet** を戻り値にすることで意図しない変更を防ぐことが可能となります。


より良い意見、似たような事してるけど違うアプローチ、違うテクニックなどコメントお待ちしております。