none
PropertyInfo.GetValueで多次元配列の要素を指定したい RRS feed

  • 質問

  • C#プログラミングしております。

    PropertyInfo.GetValueの第二引数で要素数を指定すればよいことはMSDNのサンプルにて分かりました。

    1次元配列の場合は

    GetValue( hoge , new object[]{10} )

    で要素数10番目の値を取得できました。

    2次元配列の場合は安易に

    new object[]{5,5}

    としましたがエラーが出てしまいます。

     

     どのように表記したらよいのかが分からなかったため投稿しました。

    よろしくお願いいたします。

    2011年7月21日 1:44

回答

  • Hongliangさんも返信されていますが…

    test1もtest2もプロパティとしては2次元配列ではありません。というか1次元配列でもありません。

    • test1はList<int>型を扱うプロパティ
    • test2はint[]型を扱うプロパティ

    です。どちらもインデックス付きプロパティではなく、次元はありません。GetValue()で得られたオブジェクトに対して、改めてアクセスする必要があります。

    もう少し説明すると、PropertyInfo.GetValue()は言語に依存しない中立的な実装のためにインデックス付きプロパティをサポートしますが、C#言語としては、私がサンプルとして挙げたようにインデクサーとして宣言時にはthis[ , , ]という形しかとることができません。またそのインデクサーは同じくサンプルから読み取れますがプロパティ名としては"Item"固定です。 

    • 回答としてマーク ashalu 2011年7月22日 2:01
    2011年7月22日 0:41

すべての返信

  • その書き方で合っています。サンプルを書いて確認してみました。

    class Program
    {
    	static void Main(string[] args) {
    		var sample = new Sample();
    		var x = 8;
    		var y = 3;
    		Console.WriteLine("sample[{0},{1}] = {2}", x, y, sample[x, y]);
    		var prop = sample.GetType().GetProperty("Item");
    		var value = prop.GetValue(sample, new object[] { x, y });
    		Console.WriteLine("via PropertyInfo = {0}", value);
    	}
    }
    
    public class Sample
    {
    	public int this[int x, int y] {
    		get {
    			return x * 10 + y;
    		}
    	}
    }
    
    

    そこで思ったのは、そもそもアクセスしようとしているプロパティが、2次元配列ではないということはありませんか?

    なお、質問の際に、参考にしたサンプルのアドレスや、発生したエラー内容も含めてもらえると話が進みやすいです。

    2011年7月21日 2:25
  • 回答ありがとうございます。

    回答を頂きこちらで確認したところ2次元配列であることはあったのですが、もとのソース自体に問題があったようです。

    もともと以下サンプルのようにしてprivateな配列にアクセスしていたのですが、1次元配列ではなくListで実装されていたようです。

    よって今回の問題の原因は配列自体にアクセスできていなかったというのが原因でした。


    class Program
    {
        static void Main(string[] args)
        {  //test1にはアクセスできるのですが、test2ではアクセスできません。
            var sample = new Sample();
            PropertyInfo p1 = sample.GetType().GetProperty("test1", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
            var SpCollection = p1.GetValue(sample, null);
            PropertyInfo pi2 = SpCollection.GetType().GetProperty("Item", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
            Console.WriteLine(pi2.GetValue(SpCollection, new object[] { 1 }));
        }
    }

    public class Sample
    {
        private List<int> test1 { get; set; }
        private int[] test2 { get; set; }

        public Sample()
        {
            test1 = new List<int>(new int[] { 1, 2, 3 });
            test2 = new int[] { 4, 5, 6 };
        }
    }

    詳しく理解していないのですが配列には"Item"に変わるものがあるのかな~?と

    String indexerName = ((DefaultMemberAttribute)SpCollection.GetType().GetCustomAttributes(typeof(DefaultMemberAttribute), true)[0]).MemberName;

    で調べてみたのですがどうやらないようで、別の方法を考えることにしました。

     

    質問内容の答えは頂けたので大変満足です。ありがとうございました。

     

     

    2011年7月21日 23:02
  • インデクサではなく本当に配列であるのなら、test1 と同様に test2 の PropertyInfo を取得してください。

    配列の要素を取得設定したいのなら、test2 の PropertyInfo から(もちろん第二引数は null で)GetValue したのを、 Array にキャストして Array.GetValue / Array.SetValue します。

    2011年7月21日 23:50
  • Hongliangさんも返信されていますが…

    test1もtest2もプロパティとしては2次元配列ではありません。というか1次元配列でもありません。

    • test1はList<int>型を扱うプロパティ
    • test2はint[]型を扱うプロパティ

    です。どちらもインデックス付きプロパティではなく、次元はありません。GetValue()で得られたオブジェクトに対して、改めてアクセスする必要があります。

    もう少し説明すると、PropertyInfo.GetValue()は言語に依存しない中立的な実装のためにインデックス付きプロパティをサポートしますが、C#言語としては、私がサンプルとして挙げたようにインデクサーとして宣言時にはthis[ , , ]という形しかとることができません。またそのインデクサーは同じくサンプルから読み取れますがプロパティ名としては"Item"固定です。 

    • 回答としてマーク ashalu 2011年7月22日 2:01
    2011年7月22日 0:41
  • >>もう少し説明すると、PropertyInfo.GetValue()は言語に依存しない中立的な実装のためにインデックス付きプロパティをサポートしますが、C#言語としては、私がサンプルとして挙げたようにインデクサーとして宣言時にはthis[ , , ]という形しかとることができません。またそのインデクサーは同じくサンプルから読み取れますがプロパティ名としては"Item"固定です。

    噛み砕いた解説のおかげで非常によく理解できました。ありがとうございます。

    GetValue()にて得られた値に対してのアクセスも確認することができ満足しております。

     

    2011年7月22日 2:01
  • ちょっとだけ補足、インデクサの名前は IndexerNameAttribute で変更できます。

    概ね、プロパティ名を Item から変更しないでもよい設計が推奨されていますが、そのようなクラス設計ができない場合には、他のプログラム言語からのアクセスを考慮して適切な名称を設定するべきだと考えられます。

     

    2011年7月28日 2:53