Rainbow Engine

IT技術を分かりやすく簡潔にまとめることによる学習の効率化、また日常の気付きを記録に残すことを目指します。

C#

C#のIEnumerableとは?使い方(foreachでの要素取り出し)を順を追って解説

投稿日:2021年1月1日 更新日:

<目次>

(1) C#のIEnumerableとは?使い方(foreachでの要素取り出し)を順を追って解説
 (1-1) IEnumerableとは?
 (1-2) IEnumerableの実装の流れ
  (1-2-1) STEP1:IEnumerableインターフェイスの実装
  (1-2-2) STEP2:IEnumeratorインターフェイスの実装
 (1-3) サンプルプログラムで理解を深める

(1) C#のIEnumerableとは?使い方(foreachでの要素取り出し)を順を追って解説

(1-1) IEnumerableとは?

C#のインターフェイスでカスタム配列への対話的なアクセス(foreachによるアクセス)を可能にします。

■IEnumerableの概要
IEnumerableインターフェイスは抽象メソッドGetEnumerator()メソッドのみを持つインターフェイスで、戻り値は「IEnumerator」インターフェイスを返却します。この「IEnumerator」インターフェイスを使うとカスタム配列の要素に対して、繰り返し処理でアクセスできる様になります。

(図111)

■IEnumeratorで出来る事・出来ない事
IEnumeratorインターフェイスは3つメソッドMoveNext()とReset()とCurrentがあります。「IEnumerable」を実装すると、foreachでループして要素を取得できるようになります。注意点として「IEnumerator」インターフェイスは要素に対してアクセスはできますが、変更する事はできません。

■IEnumeratorで配列にアクセスする際のお作法
通常、配列の要素にアクセスする際は「インデックス」を使いまが、IEnumeratorではインデックスの代わりに3つの抽象メソッド「Reset()」と「MoveNext()」と「Current()」を使って要素にアクセスします。

目次にもどる

(1-2) IEnumerableの実装の流れ

ここからはIEnumerableの実装の流れ

(1-2-1) STEP1:IEnumerableインターフェイスの実装

まずは最初に「IEnumerable」インターフェイスを実装します。このインターフェイスには「GetEnumerator()」メソッドがあり、我々のカスタムクラスのアクセスに使う「IEnumerator」のオブジェクトを返却します。

(例)GetEnumeratorメソッドの実装

public IEnumerator GetEnumerator()
{
	return (IEnumerator)this;
}

目次にもどる

(1-2-2) STEP2:IEnumeratorインターフェイスの実装

次に「IEnumerator」インターフェイスを実装します。このインターフェイスは下記3つのメソッドがあり、これらの3つのメソッドを実装するとforeachによるループが可能となります。

// IEnumeratorインターフェイスのメソッドシグニチャ
void Reset()
bool MoveNext()
object Current

 

①void Reset()メソッド

まずはReset()メソッドの実装です。Reset()メソッドはポインタ(現在の要素を指す変数)を開始地点にセットします(最初の要素の前に0番目の空要素があるイメージ)。ですので、インデックスとしては「-1」を割り当てています。

(例)Reset()メソッドの実装

public void Reset()
{
	[現在位置変数名] = -1;
}

目次にもどる

②bool MoveNext()メソッド

MoveNext()は次の要素に移動するためのメソッドです。内部的には現在位置(カレントポジション)の次の要素があるならばtrueを返却し、次の要素が無い場合はfalseを返却します。

(例)MoveNext()メソッドの実装

public bool MoveNext()
{
	if ([現在位置変数名] < [配列名].Count - 1)
	{
		++[現在位置変数名];
		return true;
	}
	return false;
}

目次にもどる

③object Current()メソッド

特定の位置にある要素を返却するために使います。実際に要素を順番に取り出していく際は「MoveNext ()」と「Current」を組み合わせて使っていく形になります。

(例)Current()メソッドの実装

public object Current
{
	get
	{
		return PersonList[CurrPosition];
	}
}

目次にもどる

 

(1-3) サンプルプログラムで理解を深める

理解を深めるために、サンプルプログラムを用いて実装の流れをご紹介します。例として以下のようなサンプルプログラムに対してforeachを使いたいと仮定します。

 

このプログラムは個人(Person)の情報を保持する自作クラスと、そのPersonを複数集めた「集団」を表すPeopleクラス(Personクラスの配列)の2つが主にあります。
そしてMain文の中で、Personインスタンスを作ってPeopleに追加した後に「foreach」を使ってアクセスしようとしています。

 

(サンプルプログラム:初期状態)
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace IEnumeratorTest
{
  //①個人を管理するPersonクラス
  class Person
  {
    private string FirstName;
    private string LastName;
    private int Age;
    public Person(string firstName, string lastName, int age)
    {
      this.FirstName = firstName;
      this.LastName = lastName;
      this.Age = age;
    }
    public override string ToString()
    {
      return "Name:" + FirstName + " " + LastName + " Age: " + Age.ToString();
    }
  }
  //②複数人の集団を管理するPeopleクラス
  class People
  {
    ArrayList PersonList = new ArrayList();
    public void AddPerson(Person oPeople)
    {
      PersonList.Add(oPeople);
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      //Peopleクラス(複数人の集団)のインスタンス作成
      People plist = new People();
      //Personクラス(個人)のインスタンス作成
      Person p1 = new Person("Suzuki", "Hanako", 29);
      Person p2 = new Person("Yamada", "Taro", 19);
      //People(集団)にPerson(個人)を追加
      plist.AddPerson(p1);
      plist.AddPerson(p2);
      Console.WriteLine("### foreachを用いてPersonsを数え上げ開始 ###");
      foreach (Person person in plist)
      {
        Console.WriteLine(person);
      }
    }
  }
}
ただし、このサンプルは前述の「IEnumerable」や「IEnumerator」を実装していないため、次のようにエラーになります。
エラー	CS1579	foreach ステートメントは、'People' が 'GetEnumerator' のパブリック インスタンス定義を含んでいないため、型 'People' の変数に対して使用できません	

(図131)エラー

 
このエラーを解消するために、自作クラスの配列であるPeopleに対して、「IEnumerable」や「IEnumerator」の実装を行うと、次のようになります。

 

(サンプルプログラム)
※プログラム中にある「(★追記)」が変更箇所を表しています。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace IEnumeratorTest2
{
  //①個人を管理するPersonクラス
  class Person
  {
    private string FirstName;
    private string LastName;
    private int Age;
    public Person(string firstName, string lastName, int age)
    {
      this.FirstName = firstName;
      this.LastName = lastName;
      this.Age = age;
    }
    public override string ToString()
    {
      return "Name:" + FirstName + " " + LastName + " Age: " + Age.ToString();
    }
  }
  //②複数人の集団を管理するPeopleクラス
  class People : IEnumerable, IEnumerator
  {
    ArrayList PersonList = new ArrayList();
    public void AddPerson(Person oPeople)
    {
      PersonList.Add(oPeople);
    }
    // (1) IEnumerableの実装(★追記)
    public IEnumerator GetEnumerator()
    {
      return (IEnumerator)this;
    }
    // (2) IEnumeratorの実装(★追記)
    // 現在位置(カレントポジション)の変数定義
    private int CurrPosition = -1;
    // (2-1) void Reset()メソッド(★追記)
    public bool MoveNext()
    {
      if (CurrPosition < PersonList.Count - 1)
      {
        ++CurrPosition;
        return true;
      }
      return false;
    }
    // (2-2) bool MoveNext()メソッドの実装(★追記)
    public void Reset()
    {
      CurrPosition = -1;
    }
    // (2-3) object Current()メソッドの実装(★追記)
    public object Current
    {
      get
      {
        return PersonList[CurrPosition];
      }
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      //Peopleクラス(複数人の集団)のインスタンス作成
      People plist = new People();
      //Personクラス(個人)のインスタンス作成
      Person p1 = new Person("Suzuki", "Hanako", 29);
      Person p2 = new Person("Yamada", "Taro", 19);
      //People(集団)にPerson(個人)を追加
      plist.AddPerson(p1);
      plist.AddPerson(p2);
      Console.WriteLine("### foreachを用いてPersonsを数え上げ開始 ###");
      foreach (Person person in plist)
      {
        Console.WriteLine(person);
      }
    }
  }
}

(図132)

目次にもどる

Adsense審査用広告コード


Adsense審査用広告コード


-C#

執筆者:


comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

関連記事

C#からDB接続でSQLServerに接続してSELECT文を実行する方法

<目次> (1) C#からDB接続する方法~SQLServerへの接続プログラム例もご紹介~  (1-1) 構文(DB接続)  (1-2) 構文(SELECT文発行)  (1-3) サンプルプログラム …

C#で「(407) プロキシ認証が必要です」エラーが出た時の対処方法

  <目次> (1) C#で「(407) プロキシ認証が必要です」エラーが出た時の対処方法  (1-1) エラー事象  (1-2) 原因  (1-3) 対処例  (1-4) 補足:ID/Pa …

C#のIComparerの実装方法や用法について(サンプルプログラムあり)

<目次> (1) C#のIComparerの実装方法や用法について  (1-1) IComparerの概要  (1-2) STEP0:比較をするクラスの定義  (1-3) STEP1:ICompare …

C#のvarとは?型を調べる方法や制約事項についてもご紹介

<目次> (1) C#のvarとは?型を調べる方法や制約事項についてもご紹介  (1-1) C#のvarとは?  (1-2) サンプルプログラム:varの基本動作確認#1  (1-3) サンプルプログ …

C#のエラー「CS1069~このアセンブリへの参照を追加する事を検討してください」の対処方法+実際のソース例も掲載

<目次> (1) C#のエラー「CS1069~このアセンブリへの参照を追加する事を検討してください」の対処方法  (1-1) 発生状況・エラーメッセージ  (1-2) 原因  (1-3) 対処法 (1 …

  • English (United States)
  • 日本語
Top