繁体   English   中英

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

[英]Use reflection “GetValue” to return information from Dictionary

-编辑-重写以更好地阐明我要执行的操作以及问题所在。 很抱歉,它不是简洁的,但是上下文可能有助于理解。

我有一个程序,可以在各种情况下运行许多模拟。 我将这些模拟和场景的结果存储在一个类(“结果类”)中,并将基本结果存储为该类的属性,并将各种场景和敏感度存储在该类的字典中。

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

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

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

好的。。。不是世界上最漂亮的代码,但是它可以工作(任何改进的建议都值得赞赏)。

我测试一下是否正在尝试从字典中获取值。 如果是这样,我将获得字典的名称以及所请求元素的索引。 我在Dictionary Name上使用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属性(即类的indexer属性的实际编译名称),通过反射直接访问对象。 看起来像这样:

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以及该代码的功能以及您希望其执行的操作的准确说明来改进此问题。

暂无
暂无

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

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