#region License
/*
* Copyright 2002-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.Collections;
using System.Reflection;
using System.Runtime.Serialization;
using Spring.Core;
using Spring.Util;
using Spring.Reflection.Dynamic;
namespace Spring.Expressions{
/// <summary>
/// Represents parsed indexer node in the navigation expression.
/// </summary>
/// <author>Aleksandar Seovic</author>
[Serializable]
public class IndexerNode : NodeWithArguments
{
private const BindingFlags BINDING_FLAGS
= BindingFlags.Public | BindingFlags.NonPublic
| BindingFlags.Instance | BindingFlags.Static
| BindingFlags.IgnoreCase;
private SafeProperty indexer;
/// <summary>
/// Create a new instance
/// </summary>
public IndexerNode()
{
}
/// <summary>
/// Create a new instance from SerializationInfo
/// </summary>
protected IndexerNode(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
/// <summary>
/// Returns node's value for the given context.
/// </summary>
/// <param name="context">Context to evaluate expressions against.</param>
/// <param name="evalContext">Current expression evaluation context.</param>
/// <returns>Node's value.</returns>
protected override object Get(object context, EvaluationContext evalContext)
{
if (context == null)
{
throw new NullValueInNestedPathException("Cannot retrieve the value of the indexer because the context for its resolution is null.");
}
try
{
if (context is Array)
{
return GetArrayValue( (Array) context, evalContext );
}
else if (context is IList)
{
return GetListValue( (IList) context, evalContext );
}
else if (context is IDictionary)
{
return GetDictionaryValue( (IDictionary) context, evalContext );
}
else if (context is string)
{
return GetCharacter( (string) context, evalContext );
}
else
{
return GetGenericIndexer( context, evalContext );
}
}
catch (TargetInvocationException e)
{
throw new InvalidPropertyException(evalContext.RootContextType, this.ToString(), "Getter for indexer threw an exception.", e);
}
catch (UnauthorizedAccessException e)
{
throw new InvalidPropertyException( evalContext.RootContextType,this.ToString(),"Illegal attempt to get value for the indexer.",e );
}
catch (IndexOutOfRangeException e)
{
throw new InvalidPropertyException( evalContext.RootContextType,this.ToString(),"Index out of range.",e );
}
catch (ArgumentOutOfRangeException e)
{
throw new InvalidPropertyException( evalContext.RootContextType,this.ToString(),"Argument out of range.",e );
}
catch (InvalidCastException e)
{
throw new InvalidPropertyException( evalContext.RootContextType,this.ToString(),"Invalid index type.",e );
}
catch (ArgumentException e)
{
throw new InvalidPropertyException( evalContext.RootContextType,this.ToString(),"Invalid argument.",e );
}
}
/// <summary>
/// Sets node's value for the given context.
/// </summary>
/// <param name="context">Context to evaluate expressions against.</param>
/// <param name="evalContext">Current expression evaluation context.</param>
/// <param name="newValue">New value for this node.</param>
protected override void Set(object context, EvaluationContext evalContext, object newValue)
{
if (context == null)
{
throw new NullValueInNestedPathException("Cannot set the value of the indexer because the context for its resolution is null.");
}
try
{
if (context is Array)
{
SetArrayValue( (Array) context, evalContext,newValue );
}
else if (context is IList)
{
SetListValue( (IList) context, evalContext,newValue );
}
else if (context is IDictionary)
{
SetDictionaryValue( (IDictionary) context, evalContext,newValue );
}
else
{
SetGenericIndexer( context, evalContext,newValue );
}
}
catch (TargetInvocationException e)
{
throw new InvalidPropertyException( evalContext.RootContextType,this.ToString(),"Setter for indexer threw an exception.",e );
}
catch (UnauthorizedAccessException e)
{
throw new InvalidPropertyException( evalContext.RootContextType,this.ToString(),"Illegal attempt to set value for the indexer.",e );
}
catch (IndexOutOfRangeException e)
{
throw new InvalidPropertyException( evalContext.RootContextType,this.ToString(),"Index out of range.",e );
}
catch (ArgumentOutOfRangeException e)
{
throw new InvalidPropertyException( evalContext.RootContextType,this.ToString(),"Argument out of range.",e );
}
catch (InvalidCastException e)
{
throw new InvalidPropertyException( evalContext.RootContextType,this.ToString(),"Invalid index type.",e );
}
catch (ArgumentException e)
{
throw new InvalidPropertyException( evalContext.RootContextType,this.ToString(),"Invalid argument.",e );
}
}
/// <summary>
/// Utility method that is needed by ObjectWrapper and AbstractAutowireCapableObjectFactory.
/// </summary>
/// <param name="context">Context to resolve property against.</param>
/// <param name="variables">Expression variables map.</param>
/// <returns>PropertyInfo for this node.</returns>
internal PropertyInfo GetPropertyInfo(object context, IDictionary variables)
{
lock (this)
{
EvaluationContext evalContext = new EvaluationContext(context, variables);
InitializeIndexerProperty(context, evalContext);
return indexer.PropertyInfo;
}
}
private object GetArrayValue(Array array, EvaluationContext evalContext)
{
int argCount = array.Rank;
AssertArgumentCount(argCount);
Int32[] indices = new Int32[argCount];
for (int i = 0; i < argCount; i++)
{
indices[i] = (Int32) ResolveArgument(i, evalContext);
}
return array.GetValue(indices);
}
private object GetListValue(IList list, EvaluationContext evalContext)
{
AssertArgumentCount(1);
return list[(int) ResolveArgument(0, evalContext)];
}
private object GetDictionaryValue(IDictionary dictionary, EvaluationContext evalContext)
{
AssertArgumentCount(1);
return dictionary[ResolveArgument( 0,evalContext )];
}
private object GetCharacter(string character, EvaluationContext evalContext)
{
AssertArgumentCount(1);
return character[(int)ResolveArgument( 0,evalContext )];
}
private object GetGenericIndexer(object context, EvaluationContext evalContext)
{
object[] indices = InitializeIndexerProperty( context, evalContext );
return indexer.GetValue(context, indices);
}
private void SetArrayValue(Array array, EvaluationContext evalContext,object newValue)
{
int argCount = array.Rank;
AssertArgumentCount(argCount);
Int32[] indices = new Int32[argCount];
for (int i = 0; i < argCount; i++)
{
indices[i] = (Int32) ResolveArgument(i, evalContext);
}
array.SetValue(newValue, indices);
}
private void SetListValue(IList list, EvaluationContext evalContext,object newValue)
{
AssertArgumentCount(1);
list[(int) ResolveArgument(0, evalContext)] = newValue;
}
private void SetDictionaryValue(IDictionary dictionary, EvaluationContext evalContext,object newValue)
{
AssertArgumentCount(1);
dictionary[ResolveArgument( 0,evalContext )] = newValue;
}
private void SetGenericIndexer(object context, EvaluationContext evalContext,object newValue)
{
object[] indices = InitializeIndexerProperty( context, evalContext );
indexer.SetValue( context, newValue, indices );
}
private object[] InitializeIndexerProperty(object context, EvaluationContext evalContext)
{
object[] indices = ResolveArguments( evalContext );
if (indexer == null)
{
lock (this)
{
if (indexer == null)
{
Type contextType = context.GetType();
Type[] argTypes = ReflectionUtils.GetTypes(indices);
string defaultMember = "Item";
object[] atts = contextType.GetCustomAttributes(typeof(DefaultMemberAttribute), true);
if (atts != null && atts.Length > 0)
{
defaultMember = ((DefaultMemberAttribute) atts[0]).MemberName;
}
PropertyInfo indexerProperty = contextType.GetProperty(defaultMember, BINDING_FLAGS, null, null, argTypes, null);
if (indexerProperty == null)
{
throw new ArgumentException("Indexer property with specified number and types of arguments does not exist.");
}
indexer = new SafeProperty(indexerProperty);
}
}
}
return indices;
}
}
}
|