PropertyInfo.GetValue() - how do you index into a

2020-02-28 02:46发布

问题:

This (shortened) code..

for (int i = 0; i < count; i++)
{
    object obj = propertyInfo.GetValue(Tcurrent, new object[] { i });
}

.. is throwing a 'TargetParameterCountException : Parameter count mismatch' exception.

The underlying type of 'propertyInfo' is a Collection of some T. 'count' is the number of items in the collection. I need to iterate through the collection and perform an operation on obj.

Advice appreciated.

回答1:

Reflection only works on one level at a time.

You're trying to index into the property, that's wrong.

Instead, read the value of the property, and the object you get back, that's the object you need to index into.

Here's an example:

using System;
using System.Collections.Generic;
using System.Reflection;

namespace DemoApp
{
    public class TestClass
    {
        public List<Int32> Values { get; private set; }

        public TestClass()
        {
            Values = new List<Int32>();
            Values.Add(10);
        }
    }

    class Program
    {
        static void Main()
        {
            TestClass tc = new TestClass();

            PropertyInfo pi1 = tc.GetType().GetProperty("Values");
            Object collection = pi1.GetValue(tc, null);

            // note that there's no checking here that the object really
            // is a collection and thus really has the attribute
            String indexerName = ((DefaultMemberAttribute)collection.GetType()
                .GetCustomAttributes(typeof(DefaultMemberAttribute),
                 true)[0]).MemberName;
            PropertyInfo pi2 = collection.GetType().GetProperty(indexerName);
            Object value = pi2.GetValue(collection, new Object[] { 0 });

            Console.Out.WriteLine("tc.Values[0]: " + value);
            Console.In.ReadLine();
        }
    }
}


回答2:

I was most of the way there until I saw this, and I am posting this because I didn't see it anywhere else; the key was using GetValue(collection, new Object[] { i }); in the loop rather than trying to use GetValue(collection, new Object[i]); outside the loop. (You can probably ignore the "output" in my example);

private static string Recursive(object o)
{ 
        string output="";
        Type t = o.GetType();
        if (t.GetProperty("Item") != null)
        {
            System.Reflection.PropertyInfo p = t.GetProperty("Item");
            int count = -1;
            if (t.GetProperty("Count") != null && 
                t.GetProperty("Count").PropertyType == typeof(System.Int32))
            {
                count = (int)t.GetProperty("Count").GetValue(o, null);
            }
            if (count > 0)
            {
                object[] index = new object[count];
                for (int i = 0; i < count; i++)
                {
                    object val = p.GetValue(o, new object[] { i });
                    output += RecursiveWorker(val, p, t);
                }
            }
       }
       return output;        
}


回答3:

Assembly zip_assembly = Assembly.LoadFrom(@"C:\Ionic.Zip.Reduced.dll");
Type ZipFileType = zip_assembly.GetType("Ionic.Zip.ZipFile");
Type ZipEntryType = zip_assembly.GetType("Ionic.Zip.ZipEntry");
string local_zip_file = @"C:\zipfile.zip";
object zip_file = ZipFileType.GetMethod("Read", new Type[] { typeof(string) }).Invoke(null, new object[] { local_zip_file });

// Entries is ICollection<ZipEntry>
IEnumerable entries = (IEnumerable)ZipFileType.GetProperty("Entries").GetValue(zip_file, null);
foreach (object entry in entries)
{
    string file_name = (string)ZipEntryType.GetProperty("FileName").GetValue(entry, null);
    Console.WriteLine(file_name);
}