PropertyInfo.GetValue() - 如何在 C# 中使用反射索引到泛型参数?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/937224/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 03:44:25  来源:igfitidea点击:

PropertyInfo.GetValue() - how do you index into a generic parameter using reflection in C#?

c#genericsreflection

提问by flesh

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.

.. 正在抛出“TargetParameterCountException:参数计数不匹配”异常。

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.

'propertyInfo' 的底层类型是一些 T 的集合。'count' 是集合中的项目数。我需要遍历集合并对 obj 执行操作。

Advice appreciated.

建议表示赞赏。

采纳答案by Lasse V. Karlsen

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();
        }
    }
}

回答by Lasse V. Karlsen

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);

在我看到这个之前,我大部分时间都在那里,我发布这个是因为我没有在其他任何地方看到它;关键是使用 GetValue(collection, new Object[] { i }); 在循环中而不是尝试使用 GetValue(collection, new Object[i]); 在循环之外。(您可能可以忽略我示例中的“输出”);

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;        
}

回答by zioolek

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);
}