【问题标题】:ExpandoObject with Spring expression带有 Spring 表达式的 ExpandoObject
【发布时间】:2012-05-10 06:20:25
【问题描述】:

我使用 ExpandoObject 类创建对象,我想对该对象执行 spring.net 表达式,但随后出现以下错误:

“名称”节点无法为指定的上下文解析 [System.Dynamic.ExpandoObject]。

代码如下:

  dynamic expandObject = new ExpandoObject();
  expandObject.Name = "Los";
  var value = (string)ExpressionEvaluator.GetValue(expandObject, "Name");

我认为 spring 表达式不适用于动态对象,但也许你现在为什么会发生这种情况以及任何解决方法(我尝试在 IDictionary 列表上转换 ExpandoObject 然后执行 spring 表达式,但这不起作用)?

【问题讨论】:

    标签: c# .net dynamic spring.net expandoobject


    【解决方案1】:

    我下载了Spring.Net源代码,首先注意到spring.net核心库是用.Net framework 2.0制作的,因为当前版本(1.3.2)的spring.net不能工作使用 System.Dynamic.ExpandoObject(在 .net framework 4.0 中添加)。
    正如我们现在的 System.Dynamic.ExpandoObject 是一个对象,其成员可以在运行时动态添加和删除,添加的属性和方法保存在 Dictionary 列表中。因此,我修改了 spring.net core 的源代码以支持 System.Dynamic.ExpandoObject,现在一切正常。


    我改变了什么?
    1. 我将 Spring.Net 库升级到 .NET framework 4.0
    2.我在Spring.Expressions.PropertyOrFieldNode类中修改了InitializeNode()方法:

    private void InitializeNode(object context)
        {
            Type contextType = (context == null || context is Type ? context as Type : context.GetType());
    
            if (accessor == null || accessor.RequiresRefresh(contextType))
            {
                memberName = this.getText();
    
                // clear cached member info if context type has changed (for example, when ASP.NET page is recompiled)
                if (accessor != null && accessor.RequiresRefresh(contextType))
                {
                    accessor = null;
                }
    
                // initialize this node if necessary
                if (contextType != null && accessor == null)
                {//below is new IF;)
                    if (contextType == typeof(System.Dynamic.ExpandoObject))
                    {
                        accessor = new ExpandoObjectValueAccessor(memberName);
                    }
                    // try to initialize node as enum value first
                    else if (contextType.IsEnum)
                    {
                        try
                        {
                            accessor = new EnumValueAccessor(Enum.Parse(contextType, memberName, true));
                        }
                        catch (ArgumentException)
                        {
                            // ArgumentException will be thrown if specified member name is not a valid
                            // enum value for the context type. We should just ignore it and continue processing,
                            // because the specified member could be a property of a Type class (i.e. EnumType.FullName)
                        }
                    }
    
                    // then try to initialize node as property or field value
                    if (accessor == null)
                    {
                        // check the context type first
                        accessor = GetPropertyOrFieldAccessor(contextType, memberName, BINDING_FLAGS);
    
                        // if not found, probe the Type type
                        if (accessor == null && context is Type)
                        {
                            accessor = GetPropertyOrFieldAccessor(typeof(Type), memberName, BINDING_FLAGS);
                        }
                    }
                }
    
                // if there is still no match, try to initialize node as type accessor
                if (accessor == null)
                {
                    try
                    {
                        accessor = new TypeValueAccessor(TypeResolutionUtils.ResolveType(memberName));
                    }
                    catch (TypeLoadException)
                    {
                        if (context == null)
                        {
                            throw new NullValueInNestedPathException("Cannot initialize property or field node '" +
                                                                     memberName +
                                                                     "' because the specified context is null.");
                        }
                        else
                        {
                            throw new InvalidPropertyException(contextType, memberName,
                                                               "'" + memberName +
                                                               "' node cannot be resolved for the specified context [" +
                                                               context + "].");
                        }
                    }
                }
            }
        }
    


    2. 我添加了我的自定义 ExpandoObjectValueAccessor

    private class ExpandoObjectValueAccessor : BaseValueAccessor
        {
            private string memberName;
    
            public ExpandoObjectValueAccessor(string memberName)
            {
                this.memberName = memberName;
            }
    
            public override object Get(object context)
            {
                var dictionary = context as IDictionary<string, object>;
    
                object value;
                if (dictionary.TryGetValue(memberName, out value))
                {
                    return value;
                }
                throw new InvalidPropertyException(typeof(System.Dynamic.ExpandoObject), memberName,
                                                   "'" + memberName +
                                                   "' node cannot be resolved for the specified context [" +
                                                   context + "].");
            }
    
            public override void Set(object context, object value)
            {
                throw new NotSupportedException("Cannot set the value of an expando object.");
            }
        }
    

    编辑:当然,您不必将 spring.net 核心库升级到 .net framework 4.0 - 我这样做是因为我不喜欢通过魔术字符串来组合对象类型,我更喜欢使用 typeof()

    【讨论】:

    • 实际上,spring.net 正在放弃对框架版本 jira.springframework.org/secure/BrowseProject.jspa?id=10020 上发布此问题
    • 感谢好主意,我在这里添加了这个问题jira.springsource.org/browse/… 我希望我做对了,我从未使用过 Jira
    • 看起来像春天的家伙喜欢你的解决方案;检查您的票下方的 cmets。
    • 恕我直言,throw new NotSupportedException("Cannot set the value of an enum."); 应该是 throw new NotSupportedException("Cannot set the value of an expando object.");
    • 好点,我基于 EnumValueAccessor 我自己的类,我没有改变一切;)我没有测试,但我认为 Set 方法可以与 ExpandoObject 我会做一些测试周末,我们会看到:) 我根据您的建议修改了异常消息 - 谢谢
    猜你喜欢
    • 2018-11-05
    • 2015-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-30
    • 2017-05-08
    • 1970-01-01
    相关资源
    最近更新 更多