使用反射“GetValue”从字典返回信息

本文关键字:字典 返回 信息 GetValue 反射 | 更新日期: 2023-09-27 17:57:27

--EDIT-- 重写以更好地阐明我正在尝试做什么以及问题是什么。 很抱歉它不简洁,但上下文可能有助于理解。

我有一个程序,我可以针对各种场景运行许多模拟。 我将这些模拟和场景的结果存储在一个类("结果类"(中,基本结果存储为类的属性,并将各种场景和敏感性存储在类内的字典中。

由于不同的用户希望从模拟中获得不同的输出,因此我正在尝试开发一种允许用户生成自定义报告的方法。 为此,我正在使用反射。 我使用反射来处理 Result 类中的每个属性,并使用与报表类相同的层次结构将其添加到树视图中。 然后,用户可以浏览树视图,查看每个属性,并在报表中选择所需的属性。

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

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

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

从此链接中大量借用了代码,但是当路径中的一个对象是字典时,我正在努力寻找检索相应对象的最佳方法。

我已经设法让它工作,但我希望有任何关于如何改进或使其更强大的反馈。 将字典强制转换为列表,然后通过索引获取密钥显然不是最佳选择。 我可以修改我的"路径"代码以返回字典键,但不确定如何使用反射从键中获取字典值。

代码如下:

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

使用反射“GetValue”从字典返回信息

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

测试以查看我是否尝试从字典中获取值。 如果是这样,我得到字典的名称,以及所请求元素的索引。 我在字典名称上使用 GetProperty 来获取 PropertyInfo 对象,然后在该 PropertyInfo 上使用 GetValue 来获取实际的字典。 作为处理键值对的麻烦的一种方式,我将字典强制转换为列表,然后使用索引来获取单个键值对。 然后,我调用 GetProperty("Value"( 从字典中获取所需的对象。

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

缺乏一个很好的最小、完整和可验证的例子来清楚地显示你尝试过什么,以及清楚地解释你遇到的具体困难,我不太清楚你在这里问什么。但是,似乎您可能在从字典对象中检索给定键的值时遇到问题,而该对象在编译时不知道其类型(因为如果您在编译时确实知道该类型,大概您只是强制转换为该类型,然后直接使用字典(。

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

有两种方法可以实现此目的。一种是通过反射直接访问对象,使用 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,并准确描述该代码的作用以及您希望它执行的操作来改进问题。