迭代通过反射获得的字典

时间:2016-10-28 12:02:21

标签: c# .net c#-4.0

所以我有这个代码,它应该递归地打印给定对象的所有属性及其内容。

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

它不适用于ListDictionary,我现在正在Dictionary部分工作。

问题是,我用:

提取键和值的类型
Type keyType = t.GetGenericArguments()[0];
Type valueType = t.GetGenericArguments()[1];

然后VS2013告诉我这条线路有问题:

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

它告诉我找不到类型或命名空间KeyType和valueType。 我错过了什么?

感谢。

PS:.net 4.5.1

3 个答案:

答案 0 :(得分:1)

在对泛型方法的调用中,您必须提供实际的类型名称(或从您自己的方法定义中传递泛型类型参数) - 而不是<table style="text-align:center; margin: 0 auto"> <tbody> <tr> <td>0</td> <td>4</td> </tr> <tr></tr> <tr> <td>1</td> <td>3</td> </tr> <tr></tr> <tr> <td>2</td> <td>2</td> </tr> <tr></tr> <tr> <td>3</td> <td>1</td> </tr> <tr></tr> <tr> <td>4</td> <td>0</td> </tr> <tr></tr> </tbody> </table>的实例。

答案 1 :(得分:1)

基本上是您的keyType&amp; valueTypeType类型的变量,这些变量在运行时已知,因此您必须使用反射将propValue强制转换为适当的通用词典。但是,您可以使用以下事实:为了向后兼容,Dictionary<TKey,TValue>实现非通用IDictionary接口。

因此,在您的具体情况下,替换它就足够了:

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

用这个:

foreach (DictionaryEntry kvp in (IDictionary)propValue)

答案 2 :(得分:1)

如decPL所示,您应该使用System.Collections.IDictionary。但是,您还应该更改isDict逻辑。 System.Type.IsAssignableFrom允许您检查&#34;是否可以将指定类型的实例分配给当前类型实例&#34;。以下代码显示了它的行为。

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

所以你的方法应该是这样的。

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

但是你也可以使用C#作为运算符。 as运算符将尝试对指定类型执行强制转换。如果不可能,则返回null。一些示例代码。

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

和你的方法。

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