简体   繁体   English

遍历通过反射获得的字典

[英]Iterating over dictionary obtained through reflection

So I have this code which is supposed to recursively print all the properties and their content of a given object. 因此,我有这段代码应该递归地打印给定对象的所有属性及其内容。

static public void PrintProperties(object obj, int indent)
{
    if (obj == null) return;
    string indentString = new string(' ', indent);
    Type objType = obj.GetType();
    PropertyInfo[] properties = objType.GetProperties();
    foreach (PropertyInfo property in properties)
    {
        object propValue = property.GetValue(obj, null);
        if (property.PropertyType.Assembly == objType.Assembly && !property.PropertyType.IsEnum)
        {
            Console.WriteLine("{0}{1}:", indentString, property.Name);
            PrintProperties(propValue, indent + 2);
        }
        else
        {
            if (null != propValue)
            {
                Type t = propValue.GetType();
                //Console.WriteLine(":::::{0}:::::", propValue.GetType());
                bool isDict = t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Dictionary<,>);
                if (isDict)
                {
                    Type keyType = t.GetGenericArguments()[0];
                    Type valueType = t.GetGenericArguments()[1];
                    foreach (KeyValuePair<keyType, valueType> kvp in (Dictionary<keyType, valueType>)propValue)
                    {
                        Console.WriteLine(string.Format("Key = {0}, Value = {1}", kvp.Key, kvp.Value));
                    }
                }
            }

            Console.WriteLine("{0}{1}: {2}", indentString, property.Name, propValue);
        }
    }
}

It doesn't work for List and Dictionary yet, I'm working on the Dictionary part right now. 它不适用于ListDictionary ,我现在正在研究Dictionary部分。

Problem is, I extract the type of the key and value with: 问题是,我使用以下方法提取键和值的类型:

Type keyType = t.GetGenericArguments()[0];
Type valueType = t.GetGenericArguments()[1];

But then VS2013 tells me that there is a problem with this line: 但是然后VS2013告诉我这条线有问题:

foreach (KeyValuePair<keyType, valueType> kvp in (Dictionary<keyType, valueType>)propValue)

It tells me that the type or namespace KeyType and valueType are not found. 它告诉我找不到类型或名称空间KeyType和valueType。 What am I missing? 我想念什么?

Thanks. 谢谢。

PS : .net 4.5.1 PS:.net 4.5.1

在调用通用方法时,您必须提供实际的类型名称(或从您自己的方法的定义中传递通用类型参数),而不是Type实例。

Basically your keyType & valueType are variables of type Type , which are known at runtime, so you'd have to use reflection to cast your propValue to an appropriate generic Dictionary. 基本上, keyTypevalueTypeType变量,在运行时是已知的,因此您必须使用反射将propValue转换为适当的通用Dictionary。 You can however use the fact that, for backwards compatibility, Dictionary<TKey,TValue> implements the non generic IDictionary interface. 但是,您可以使用以下事实:为了向后兼容, Dictionary<TKey,TValue>实现了非通用IDictionary接口。

So in your specific case, it would be enough to replace this: 因此,在您的特定情况下,只需替换以下内容即可:

foreach (KeyValuePair<keyType, valueType> kvp in (Dictionary<keyType, valueType>)propValue)

with this: 有了这个:

foreach (DictionaryEntry kvp in (IDictionary)propValue)

As decPL indicated, you should use System.Collections.IDictionary. 如decPL所示,您应该使用System.Collections.IDictionary。 However you should also change your isDict logic. 但是,您还应该更改isDict逻辑。 System.Type.IsAssignableFrom allows you to check if "an instance of a specified type can be assigned to the current type instance". System.Type.IsAssignableFrom允许您检查“是否可以将指定类型的实例分配给当前类型实例”。 Here is code showing it's behavior. 这是显示其行为的代码。

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

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Testing System.Type.IsAssignableFrom");

            var propValue = new Dictionary<string, string>() { { "hello", "world" } };
            var t = propValue.GetType();
            bool isDict = typeof(IDictionary).IsAssignableFrom(t);
            if (isDict)
            {
                foreach (DictionaryEntry kvp in (IDictionary)propValue)
                {
                    Console.WriteLine(string.Format("Key = {0}, Value = {1}", kvp.Key, kvp.Value));
                }
            }

            Console.ReadLine();
        }
    }
}

So your method should look like this. 因此,您的方法应如下所示。

static public void PrintProperties(object obj, int indent)
{
    if (obj == null) return;
    string indentString = new string(' ', indent);
    Type objType = obj.GetType();
    PropertyInfo[] properties = objType.GetProperties();
    foreach (PropertyInfo property in properties)
    {
        object propValue = property.GetValue(obj, null);
        if (property.PropertyType.Assembly == objType.Assembly && !property.PropertyType.IsEnum)
        {
            Console.WriteLine("{0}{1}:", indentString, property.Name);
            PrintProperties(propValue, indent + 2);
        }
        else
        {
            if (null != propValue)
            {
                Type t = propValue.GetType();
                //Console.WriteLine(":::::{0}:::::", propValue.GetType());
                bool isDict = typeof(IDictionary).IsAssignableFrom(t);
                if (isDict)
                {
                    foreach (DictionaryEntry kvp in (IDictionary)propValue)
                    {
                        Console.WriteLine(string.Format("Key = {0}, Value = {1}", kvp.Key, kvp.Value));
                    }
                }
            }

            Console.WriteLine("{0}{1}: {2}", indentString, property.Name, propValue);
        }
    }
}

However you could also do this with the C# as operator. 但是,您也可以使用C#作为运算符来执行此操作。 The as operator will attempt to do a cast to the specified type. as运算符将尝试将类型强制转换为指定的类型。 If it is not possible, it returns null. 如果不可能,则返回null。 Some sample code. 一些示例代码。

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

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Testing System.Type.IsAssignableFrom");

            var propValue = new Dictionary<string, string>() { { "hello", "world" } };
            IDictionary asDict = propValue as IDictionary;
            if (asDict != null)
            {
                foreach (DictionaryEntry kvp in (IDictionary)propValue)
                {
                    Console.WriteLine(string.Format("Key = {0}, Value = {1}", kvp.Key, kvp.Value));
                }
            }

            Console.ReadLine();
        }
    }
}

And your method. 和你的方法。

static public void PrintProperties(object obj, int indent)
{
    if (obj == null) return;
    string indentString = new string(' ', indent);
    Type objType = obj.GetType();
    PropertyInfo[] properties = objType.GetProperties();
    foreach (PropertyInfo property in properties)
    {
        object propValue = property.GetValue(obj, null);
        if (property.PropertyType.Assembly == objType.Assembly && !property.PropertyType.IsEnum)
        {
            Console.WriteLine("{0}{1}:", indentString, property.Name);
            PrintProperties(propValue, indent + 2);
        }
        else
        {
            if (null != propValue)
            {
                var asDict = propValue as IDictionary;
                if (asDict != null)
                {
                    foreach (DictionaryEntry kvp in asDict)
                    {
                        Console.WriteLine(string.Format("Key = {0}, Value = {1}", kvp.Key, kvp.Value));
                    }
                }
            }

            Console.WriteLine("{0}{1}: {2}", indentString, property.Name, propValue);
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM