Example #1
0
        protected internal override IValueRef GetValueRef(ExpressionState state)
        {
            var         context          = state.GetActiveContextObject();
            var         target           = context.Value;
            var         targetDescriptor = context.TypeDescriptor;
            ITypedValue indexValue;
            object      index;

            // This first part of the if clause prevents a 'double dereference' of the property (SPR-5847)
            if (target is System.Collections.IDictionary && (_children[0] is PropertyOrFieldReference reference1))
            {
                var reference = reference1;
                index      = reference.Name;
                indexValue = new TypedValue(index);
            }
            else
            {
                // In case the map key is unqualified, we want it evaluated against the root object
                // so temporarily push that on whilst evaluating the key
                try
                {
                    state.PushActiveContextObject(state.RootContextObject);
                    indexValue = _children[0].GetValueInternal(state);
                    index      = indexValue.Value;
                    if (index == null)
                    {
                        throw new InvalidOperationException("No index");
                    }
                }
                finally
                {
                    state.PopActiveContextObject();
                }
            }

            // Raise a proper exception in case of a null target
            if (target == null)
            {
                throw new SpelEvaluationException(StartPosition, SpelMessage.CANNOT_INDEX_INTO_NULL_VALUE);
            }

            // At this point, we need a TypeDescriptor for a non-null target object
            if (targetDescriptor == null)
            {
                throw new InvalidOperationException("No type descriptor");
            }

            // Indexing into a Map
            if (target is System.Collections.IDictionary)
            {
                var key        = index;
                var mapkeyType = ReflectionHelper.GetMapKeyTypeDescriptor(targetDescriptor);
                if (mapkeyType != null)
                {
                    key = state.ConvertValue(key, mapkeyType);
                }

                _indexedType = IndexedType.MAP;
                return(new MapIndexingValueRef(this, state.TypeConverter, (IDictionary)target, key, targetDescriptor));
            }

            // If the object is something that looks indexable by an integer,
            // attempt to treat the index value as a number
            if (target is Array || target is IList || target is string)
            {
                var idx = (int)state.ConvertValue(index, typeof(int));
                if (target is Array)
                {
                    _indexedType = IndexedType.ARRAY;
                    return(new ArrayIndexingValueRef(this, state.TypeConverter, target, idx, targetDescriptor));
                }
                else if (target is IList list)
                {
                    _indexedType = IndexedType.LIST;

                    return(new CollectionIndexingValueRef(this, list, idx, targetDescriptor, state.TypeConverter, state.Configuration.AutoGrowCollections, state.Configuration.MaximumAutoGrowSize));
                }
                else
                {
                    _indexedType = IndexedType.STRING;
                    return(new StringIndexingLValue(this, (string)target, idx, targetDescriptor));
                }
            }

            // Try and treat the index value as a property of the context object
            // Could call the conversion service to convert the value to a String
            var valueType = indexValue.TypeDescriptor;

            if (valueType != null && typeof(string) == valueType)
            {
                _indexedType = IndexedType.OBJECT;
                return(new PropertyIndexingValueRef(this, target, (string)index, state.EvaluationContext, targetDescriptor));
            }

            throw new SpelEvaluationException(StartPosition, SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE, targetDescriptor);
        }