使用反射“GetValue”从Dictionary

时间:2016-07-18 03:12:38

标签: c# dictionary reflection

- 编辑 - 重写以更好地阐明我想要做的事情,以及问题是什么。抱歉它不简洁,但背景可能有助于理解。

我有一个程序,我可以针对各种场景运行大量模拟。我将这些模拟和场景的结果存储在一个类(“结果类”)中,基本结果存储为类的属性,以及存储在类中字典中的各种场景和敏感度。

由于不同的用户需要模拟的不同输出,我正在尝试开发一种允许用户生成自定义报告的方法。要做到这一点,我正在使用反射。我使用反射来处理Results类中的每个Property,并使用与Report Class相同的层次结构将其添加到树视图中。然后,用户可以浏览树视图,查看每个属性,并在报告中选择他们想要的属性。

当用户选择要报告的属性时,我使用树层次结构将其转换为“路径” - 一个定界字符串,用于描述感兴趣项目的属性分支:例如:

Results.TotalCapacity; or:
Results.UsableCapacity; or
Results.Scenarios[HighCase].TotalCapacity; or
Results.Sensitivity.ModifiedCapacity.

最终,我想使用反射来解析这些路径,并从中检索值。

我从this link大量借用了代码,但是当路径中的一个对象是字典时,我正在努力寻找合适对象的最佳方法。

我已经设法让这个工作,但我很感激任何关于如何改进或变得更强大的反馈。将字典转换为列表然后通过索引获取密钥显然不是最佳选择。我可以修改我的'path'代码来返回字典键,但不知道如何使用反射从键中获取字典值。

代码如下:

public object GetPropertyValueFromPath(object baseObject, string path)
{
    //Split into the base path elements
    string[] pp = CorrectPathForDictionaries(path).Split(new[]{ '.' }, StringSplitOptions.RemoveEmptyEntries);

    //Set initial value of the ValueObject
    object valueObject = baseObject;            
    foreach (var prop in pp)
    {
        if (prop.Contains("["))
        {
            //Will be a dictionary.  Get the name of the dictionary, and the index element of interest:
            string dictionary = prop.Substring(0, prop.IndexOf("["));
            int index = Convert.ToInt32(prop.Substring(prop.IndexOf("[") + 1, prop.Length - prop.IndexOf("]")));

            //Get the property info for the dictionary
            PropertyInfo dictInfo = valueObject.GetType().GetProperty(dictionary);
            if (dictInfo != null)
            {
                //Get the dictionary from the PropertyInformation
                valueObject = dictInfo.GetValue(valueObject, null);
                //Convert it to a list to provide easy access to the item of interest.  The List<> will be a set of key-value pairs.
                List<object> values = ((IEnumerable)valueObject).Cast<object>().ToList();
                //Use "GetValue" with the "value" parameter and the index to get the list object we want.
                valueObject = values[index].GetType().GetProperty("Value").GetValue(values[index], null); 
            }
        }
        else
        {
            PropertyInfo propInfo = valueObject.GetType().GetProperty(prop);
            if (propInfo != null)
            {
                valueObject = propInfo.GetValue(valueObject, null);
            }
        }
    }
    return valueObject;
}

2 个答案:

答案 0 :(得分:0)

好的......不是世界上最漂亮的代码,但它有效(任何改进的建议都会受到赞赏)。

我测试是否尝试从字典中获取值。如果是这样,我得到字典的名称,以及请求的元素的索引。我在Dictionary Name上使用GetProperty来获取PropertyInfo对象,然后在PropertyInfo上使用GetValue来获取实际的字典。作为一种处理键值对的方法,我将字典转换为列表,然后使用索引获取单个键值对。然后我调用GetProperty(&#34; Value&#34;)从字典中获取所需的对象。

public object GetPropertyValueFromPath(object baseObject, string path)
    {
        //Split into the base path elements
        string[] pp = CorrectPathForDictionaries(path).Split(new[]{ '.' }, StringSplitOptions.RemoveEmptyEntries);

        //Set initial value of the ValueObject
        object valueObject = baseObject;            
        foreach (var prop in pp)
        {
            if (prop.Contains("["))
            {
                //Will be a dictionary.  Get the name of the dictionary, and the index element of interest:
                string dictionary = prop.Substring(0, prop.IndexOf("["));
                int index = Convert.ToInt32(prop.Substring(prop.IndexOf("[") + 1, prop.Length - prop.IndexOf("]")));

                //Get the property info for the dictionary
                PropertyInfo dictInfo = valueObject.GetType().GetProperty(dictionary);
                if (dictInfo != null)
                {
                    //Get the dictionary from the PropertyInformation
                    valueObject = dictInfo.GetValue(valueObject, null);
                    //Convert it to a list to provide easy access to the item of interest.  The List<> will be a set of key-value pairs.
                    List<object> values = ((IEnumerable)valueObject).Cast<object>().ToList();
                    //Use "GetValue" with the "value" parameter and the index to get the list object we want.
                    valueObject = values[index].GetType().GetProperty("Value").GetValue(values[index], null); 
                }
            }
            else
            {
                PropertyInfo propInfo = valueObject.GetType().GetProperty(prop);
                if (propInfo != null)
                {
                    valueObject = propInfo.GetValue(valueObject, null);
                }
            }
        }
        return valueObject;
    }

答案 1 :(得分:0)

缺乏一个很好的Minimal, Complete, and Verifiable example,清楚地显示了你所尝试的内容,并清楚地解释了你所遇到的具体困难,我不清楚你在这里问什么。但是,它似乎可能你在从编译时不知道类型的字典对象中检索给定键的值时遇到了问题(因为如果你在编译时知道了类型的话)时间,大概你只是投射到那种类型,然后直接使用字典。)

如果这是正确的,那么这应该有所帮助:

有两种方法可以实现这一目标。一种是通过反射直接访问对象,使用Item属性,该属性是类的索引器属性的实际编译名称。这看起来像这样:

private static string GetValue(object dictionary, object key)
{
    PropertyInfo itemProperty = dictionary.GetType().GetProperty("Item");

    return itemProperty.GetValue(dictionary, new object[] { key }).ToString();
}

直接反映:获取PropertyInfo对象,然后将key值传递给GetValue()方法以获取值。

这很好用,但它有点笨拙,每次想要获取值时都需要通过反射来检查类型。您可以通过缓存PropertyInfo对象来改进后者,但它仍然是笨拙的。

您可以让运行时执行缓存工作,同时允许代码通过使用dynamic类型更准确地读取正常字典查找的内容:

private static string GetValue(dynamic dictionary, dynamic key)
{
    return dictionary[key].ToString();
}

请注意,dictionary对象和key都需要dynamic。以这种方式编写方法时,在运行时将根据dynamic变量的类型和使用它们的代码表达式创建“绑定器”。本质上,代码表达式的最终编译推迟到运行时类型已知,因此可以正常执行。 (如果要使用不同类型执行相同的语句,运行时将为每种类型组合创建不同的绑定器。)

其中任何一个都解决了在编译时未知类型时获取给定键值的具体问题。如果这不能解决您的问题,请通过提供所需的良好MCVE以及对该代码的作用以及您希望它做什么的精确描述来改进问题。