きな粉もち.net

.NET関連仕事に携わっています。OSSのソースを読んで気がついたことを中心に呟いたりブログに投稿したりしています。最近はUiPathを使ったRPAも研究中。気軽にフォローやツッコミよろしくおねがいします! Gitはここを使っています https://github.com/kinakomotitti

C# × for文 × カウンターについての間違った認識を正してみた

この記事の目的

この記事では、
自分が持っていたfor文についての間違った認識を正すこと
を目的としています。

本題

★基本のき!for文の書き方

C#を初めてすぐにであうことになる基本的な構文に「for文」があります。
Visual Studioコードスニペット機能によって、
[for] + [tabキー] + [tabキー]
と打てば 以下のように入力することができます。

for (int i = 0; i < length; i++)
{

}

コードスニペットを多用することで、for文の書き方を忘れてしまうことが多々ありますがそれは別の話・・・)
上記のコードのように、for文では、カウンター( i )を利用して繰り返し処理を実現します。
カウンターをインクリメントもしくは、デクリメントし、
定義した条件( i < length )がfalseになったときに繰り返し処理を終え、その後の処理へ進みます。


Log4netのとあるクラスにて・・・

log4netのコードを読みつつ実装を学んでいたところ、以下のコードに出会いました。

//Logger.cs
virtual public Level EffectiveLevel
{
	get 
	{
		for(Logger c = this; c != null; c = c.m_parent) 
		{
			Level level = c.m_level;

			// Casting level to Object for performance, otherwise the overloaded operator is called
			if ((object)level != null) 
			{
				return level;
			}
		}
		return null; // If reached will cause an NullPointerException.
	}
}

個人的に衝撃的だったのはfor(Logger c = this; c != null; c = c.m_parent) の部分です。


カウンターがint型じゃないのです(*´Д`)


ここでは、カウンターに「今のLoggerクラスのインスタンス(自分自身)」を定義しています。
Loggerクラスでは、親のLoggerクラスのインスタンスをm_parent変数に格納しています。
イメージとしては以下のようなものになります。

Logger(親A)
m_parent = null
└─Logger(親B)
m_parent = Logger(親A)
└─Logger(実行中のLogger)
m_parent = Logger(親B)


上記の状態のとき、

  1. 開始を自分自身に設定し、(Logger c = this)
  2. 次の値として今のLoggerの親を指定する(c = c.m_parent)
  3. 親がいなくなったらループを抜ける(c != null)

という条件のfor文を実装することができます。


★正しい考え方を整理

MSDNには以下のように記載されています。
for (C# リファレンス) | Microsoft Docs

for ループを使うと、指定した式が false と評価されるまで、ステートメントまたはステートメント ブロックを繰り返し実行することができます。 この種類のループは、配列の反復処理などループの反復回数が事前にわかっている用途に使用します。

class ForLoopTest 
{
    static void Main() 
    {
        for (int i = 1; i <= 5; i++)
        {
            Console.WriteLine(i);
        }
    }
}

まぁ、どこにもinit-expressionがintであるとは書かれていませんね(*´Д`)


まとめ

今回log4netさんに教えていただいた自分の過ちは、・・・

for文 → カウンター → int型しか指定できない

という間違った考え方でした。
同じように間違えて覚えている初心者の開発者を見つけたらこそっと指摘してあげてください(=_=)