C#でclassのフィールドなどをインデックスで扱う方法
C#でクラスメンバを扱うとき[index]のように扱えると便利だが,Marshalの関係でメンバ数を固定にしないといけない場合がある.その場合にもインデックスで変数を扱う方法を確認.
System.Reflection.dllを使用する.
例えばフィールドならFieldInfoクラスを使う.
下の例では,
(FieldInfo)typeof(SampleA).GetField("item" + (i + 1))
で取得できるFieldInfoを使ってGetValueを使う.
代入の時には,SetValueを使用することができる(プロパティならGetProperty / SetProperty).
GetField()で取得できるのはpublic属性が付いているものに限る.privateになっているフィールドを取ろうとすると例外が発生する.実行時でないとわからないのでわかりにくいバグを発生する.ただし,「public / private」に関係なくプロパティを取得することは仕様としてはできる.デバッガーはこの仕組みを利用してデバッグを行うことができる.
一人でプログラムしている場合には気にならないが,複数人でプログラムしている場合には,ほかの人の部品の公開意図のないものを扱ってしまうのは,ややリスクがある.
この方法でだけ変数を使用していた場合,Visual Studio などでは変数の使用を検知できないのでCS0414が発生する,
using System; using System.Reflection; namespace Sample1 { class Program { static void Main(string[] args) { SampleA sampleA = new SampleA() { item1 = 1, item2 = 2, item3 = 3, }; SampleA sampleA2 = new SampleA() { item1 = 11, item2 = 12, item3 = 13, }; for (int i = 0; i < 3; i++) { Int32 item = (Int32)((FieldInfo)typeof(SampleA).GetField("item" + (i + 1))).GetValue(sampleA); Console.WriteLine($"{item}"); } for (int i = 0; i < 3; i++) { Int32 item = (Int32)((FieldInfo)typeof(SampleA).GetField("item" + (i + 1))).GetValue(sampleA2); Console.WriteLine($"{item}"); } } } public class SampleA { public Int32 item1; public Int32 item2; public Int32 item3; } }
Tupleもこんな感じに扱える.(もちろん,Tupleはフィールド名を明示的に指定できるので状況によっては少し使い方が変わるかもしれないが)
Tuple<double, double, double> tuple = new Tuple<double, double, double>(0, 1, 2); for (int i = 0; i < 3; i++) { double item = (double)((PropertyInfo)typeof(Tuple<double, double, double>).GetProperty("Item" + (i + 1))).GetValue(tuple); Console.WriteLine($"{item}"); }
さてGetField以外にGetFieldsなるものがある.これが,求める「インデックスで扱う」ためのメソッドである.