From ada35f07f4c46ff647e4ac28bb7c154a2bbee370 Mon Sep 17 00:00:00 2001 From: Marko Lahma Date: Sun, 28 Oct 2018 18:29:50 +0200 Subject: [PATCH] #164 tweak object instantiation hot paths --- .../Config/ConstructorArgumentValues.cs | 86 +++++--- .../Factory/Config/ExpressionHolder.cs | 33 +-- .../Factory/Config/ObjectDefinitionVisitor.cs | 2 +- .../AbstractAutowireCapableObjectFactory.cs | 56 +++-- .../Support/AbstractObjectDefinition.cs | 6 +- .../Factory/Support/AbstractObjectFactory.cs | 35 ++- .../Objects/Factory/Support/AutowireUtils.cs | 28 ++- .../Factory/Support/ConstructorResolver.cs | 204 ++++++++++-------- .../Support/ObjectDefinitionValueResolver.cs | 42 ++-- .../Factory/Support/RootObjectDefinition.cs | 3 + .../Spring.Core/Objects/ObjectWrapper.cs | 98 +++------ src/Spring/Spring.Core/Util/AssertUtils.cs | 3 + .../Spring.Core/Util/ReflectionUtils.cs | 14 +- .../Spring.Benchmark/Spring.Benchmark.csproj | 2 +- 14 files changed, 311 insertions(+), 301 deletions(-) diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/ConstructorArgumentValues.cs b/src/Spring/Spring.Core/Objects/Factory/Config/ConstructorArgumentValues.cs index 78e296d3..b3926d31 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/ConstructorArgumentValues.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/ConstructorArgumentValues.cs @@ -42,13 +42,13 @@ namespace Spring.Objects.Factory.Config private static readonly CultureInfo enUSCultureInfo = new CultureInfo("en-US", false); private static readonly IReadOnlyDictionary _emptyIndexedArgumentValues = new Dictionary(); - private Dictionary _indexedArgumentValues = null; + internal Dictionary _indexedArgumentValues = null; private static readonly IReadOnlyList _emptyGenericArgumentValues = new List(); - private List _genericArgumentValues = null; + internal List _genericArgumentValues = null; - private static readonly IReadOnlyDictionary _emptyNamedArgumentValues = new Dictionary(); - private Dictionary _namedArgumentValues = null; + private static readonly IReadOnlyDictionary _emptyNamedArgumentValues = new Dictionary(); + internal Dictionary _namedArgumentValues = null; /// /// Can be used as an argument filler for the @@ -101,7 +101,7 @@ namespace Spring.Objects.Factory.Config /// s /// as values. /// - public IReadOnlyDictionary NamedArgumentValues => _namedArgumentValues ?? _emptyNamedArgumentValues; + public IReadOnlyDictionary NamedArgumentValues => _namedArgumentValues ?? _emptyNamedArgumentValues; /// /// Return the set of generic argument values. @@ -115,19 +115,54 @@ namespace Spring.Objects.Factory.Config /// /// Return the number of arguments held in this instance. /// - public int ArgumentCount => IndexedArgumentValues.Count - + GenericArgumentValues.Count - + NamedArgumentValues.Count; + public int ArgumentCount + { + get + { + int count = 0; + if (_indexedArgumentValues != null) + { + count += _indexedArgumentValues.Count; + } + if (_genericArgumentValues != null) + { + count += _genericArgumentValues.Count; + } + if (_namedArgumentValues != null) + { + count += _namedArgumentValues.Count; + } + + return count; + } + } /// /// Returns true if this holder does not contain any argument values, /// neither indexed ones nor generic ones. /// - public bool Empty => IndexedArgumentValues.Count == 0 - && GenericArgumentValues.Count == 0 - && NamedArgumentValues.Count == 0; + public bool Empty + { + get + { + if (_indexedArgumentValues != null && _indexedArgumentValues.Count > 0) + { + return false; + } + if (_genericArgumentValues != null && _genericArgumentValues.Count > 0) + { + return false; + } + if (_namedArgumentValues != null && _namedArgumentValues.Count > 0) + { + return false; + } - /// + return true; + } + } + + /// /// Copy all given argument values into this object. /// /// @@ -166,20 +201,13 @@ namespace Spring.Objects.Factory.Config } } - private void AddOrMergeNamedArgumentValues(string key, object newValue) - { - var namedArgumentValues = GetAndInitializeNamedArgumentValuesIfNeeded(); - if (namedArgumentValues.ContainsKey(key)) - { - namedArgumentValues[key] = newValue; - } - else - { - namedArgumentValues.Add(key, newValue); - } - } + private void AddOrMergeNamedArgumentValues(string key, ValueHolder newValue) + { + var namedArgumentValues = GetAndInitializeNamedArgumentValuesIfNeeded(); + namedArgumentValues[key] = newValue; + } - private void AddOrMergeIndexedArgumentValues(int key, ValueHolder newValue) + private void AddOrMergeIndexedArgumentValues(int key, ValueHolder newValue) { var dictionary = GetAndInitializeIndexedArgumentValuesIfNeeded(); @@ -278,7 +306,7 @@ namespace Spring.Objects.Factory.Config ValueHolder valueHolder = null; if (name != null && ContainsNamedArgument(name)) { - valueHolder = (ValueHolder) GetAndInitializeNamedArgumentValuesIfNeeded()[GetCanonicalNamedArgument(name)]; + valueHolder = GetAndInitializeNamedArgumentValuesIfNeeded()[GetCanonicalNamedArgument(name)]; } return valueHolder; @@ -572,9 +600,9 @@ namespace Spring.Objects.Factory.Config return _indexedArgumentValues = _indexedArgumentValues ?? new Dictionary(); } - private Dictionary GetAndInitializeNamedArgumentValuesIfNeeded() + private Dictionary GetAndInitializeNamedArgumentValuesIfNeeded() { - return _namedArgumentValues = _namedArgumentValues ?? new Dictionary(); + return _namedArgumentValues = _namedArgumentValues ?? new Dictionary(); } private List GetAndInitializeGenericArgumentValuesIfNeeded() @@ -624,7 +652,7 @@ namespace Spring.Objects.Factory.Config public ValueHolder Copy() { - ValueHolder copy = new ValueHolder(this._ctorValue, this.typeName); + ValueHolder copy = new ValueHolder(_ctorValue, typeName); return copy; } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/ExpressionHolder.cs b/src/Spring/Spring.Core/Objects/Factory/Config/ExpressionHolder.cs index fb16d129..1c2cff7c 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/ExpressionHolder.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/ExpressionHolder.cs @@ -1,7 +1,5 @@ -#region License - /* - * Copyright © 2002-2011 the original author or authors. + * Copyright © 2002-2011 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. @@ -16,16 +14,10 @@ * limitations under the License. */ -#endregion - -#region Imports - using System; using System.Globalization; using Spring.Expressions; -#endregion - namespace Spring.Objects.Factory.Config { /// @@ -37,16 +29,10 @@ namespace Spring.Objects.Factory.Config [Serializable] public class ExpressionHolder { - #region Fields - - private IExpression expression; + private IExpression expression; private string expressionString; private MutablePropertyValues properties; - #endregion - - #region Constructor (s) / Destructor - /// /// Creates a new instance of the /// @@ -59,11 +45,7 @@ namespace Spring.Objects.Factory.Config this.expression = Spring.Expressions.Expression.Parse(expression); } - #endregion - - #region Properties - - /// + /// /// Gets or sets the expression string. Setting the expression string will cause /// the expression to be parsed. /// @@ -90,20 +72,13 @@ namespace Spring.Objects.Factory.Config set { properties = value; } } - #endregion - - #region Methods - /// /// Returns a string representation of this instance. /// /// A string representation of this instance. public override string ToString() { - return string.Format( - CultureInfo.InvariantCulture, "<{0}>", expressionString); + return $"<{expressionString}>"; } - - #endregion } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/ObjectDefinitionVisitor.cs b/src/Spring/Spring.Core/Objects/Factory/Config/ObjectDefinitionVisitor.cs index 386e22b1..4164c32b 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/ObjectDefinitionVisitor.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/ObjectDefinitionVisitor.cs @@ -145,7 +145,7 @@ namespace Spring.Objects.Factory.Config /// specified IVariableSource. /// /// The named argument values. - protected virtual void VisitNamedArgumentValues(IReadOnlyDictionary nav) + protected virtual void VisitNamedArgumentValues(IReadOnlyDictionary nav) { foreach (ConstructorArgumentValues.ValueHolder valueHolder in nav.Values) { diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractAutowireCapableObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractAutowireCapableObjectFactory.cs index c6b809ea..5d48abfa 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractAutowireCapableObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractAutowireCapableObjectFactory.cs @@ -300,9 +300,9 @@ namespace Spring.Objects.Factory.Support $"the instantiation of '{objectName}'."); } - for (var i = 0; i < ObjectPostProcessors.Count; i++) + for (var i = 0; i < objectPostProcessors.Count; i++) { - IObjectPostProcessor processor = ObjectPostProcessors[i]; + IObjectPostProcessor processor = objectPostProcessors[i]; IInstantiationAwareObjectPostProcessor inProc = processor as IInstantiationAwareObjectPostProcessor; object theObject = inProc?.PostProcessBeforeInstantiation(objectType, objectName); if (theObject != null) @@ -841,17 +841,19 @@ namespace Spring.Objects.Factory.Support protected internal override object InstantiateObject(string name, RootObjectDefinition definition, object[] arguments, bool allowEagerCaching, bool suppressConfigure) { // guarantee the initialization of objects that the current one depends on.. - if (definition.DependsOn != null && definition.DependsOn.Count > 0) + if (definition.dependsOn != null) { - foreach (string dependant in definition.DependsOn) + for (var i = 0; i < definition.dependsOn.Count; i++) { + string dependant = definition.dependsOn[i]; GetObject(dependant); } } - if (log.IsDebugEnabled) + var isDebugEnabled = log.IsDebugEnabled; + if (isDebugEnabled) { - log.Debug(string.Format(CultureInfo.InvariantCulture, "Creating instance of Object '{0}' with merged definition [{1}].", name, definition)); + log.Debug($"Creating instance of Object '{name}' with merged definition [{definition}]."); } // Make sure object type is actually resolved at this point. @@ -873,12 +875,7 @@ namespace Spring.Objects.Factory.Support return definition; } - - - object instance = null; - - - IObjectWrapper instanceWrapper = null; + object instance; bool eagerlyCached = false; try { @@ -892,17 +889,16 @@ namespace Spring.Objects.Factory.Support } } - - instanceWrapper = CreateObjectInstance(name, definition, arguments); + var instanceWrapper = CreateObjectInstance(name, definition, arguments); instance = instanceWrapper.WrappedInstance; // eagerly cache singletons to be able to resolve circular references // even when triggered by lifecycle interfaces like IObjectFactoryAware. if (allowEagerCaching && definition.IsSingleton) { - if (log.IsDebugEnabled) + if (isDebugEnabled) { - log.Debug("Eagerly caching object '" + name + "' to allow for resolving potential circular references"); + log.Debug($"Eagerly caching object '{name}' to allow for resolving potential circular references"); } AddEagerlyCachedSingleton(name, definition, instance); eagerlyCached = true; @@ -1041,9 +1037,9 @@ namespace Spring.Objects.Factory.Support { if (HasInstantiationAwareObjectPostProcessors) { - for (var i = 0; i < ObjectPostProcessors.Count; i++) + for (var i = 0; i < objectPostProcessors.Count; i++) { - IObjectPostProcessor objectPostProcessor = ObjectPostProcessors[i]; + IObjectPostProcessor objectPostProcessor = objectPostProcessors[i]; if (ObjectUtils.IsAssignable(typeof(SmartInstantiationAwareObjectPostProcessor), objectPostProcessor)) { @@ -1769,7 +1765,7 @@ namespace Spring.Objects.Factory.Support if (log.IsDebugEnabled) { - log.Debug(string.Format("Configuring object using definition '{1}'", instance, name)); + log.Debug($"Configuring object using definition '{name}'"); } PopulateObject(name, definition, wrapper); @@ -1779,7 +1775,7 @@ namespace Spring.Objects.Factory.Support { if (log.IsDebugEnabled) { - log.Debug(string.Format(CultureInfo.InvariantCulture, "Setting the name property on the IObjectNameAware object '{0}'.", name)); + log.Debug($"Setting the name property on the IObjectNameAware object '{name}'."); } ((IObjectNameAware)instance).ObjectName = name; @@ -1790,8 +1786,7 @@ namespace Spring.Objects.Factory.Support if (log.IsDebugEnabled) { log.Debug( - string.Format(CultureInfo.InvariantCulture, "Setting the ObjectFactory property on the IObjectFactoryAware object '{0}'.", - name)); + $"Setting the ObjectFactory property on the IObjectFactoryAware object '{name}'."); } ((IObjectFactoryAware)instance).ObjectFactory = this; @@ -1907,13 +1902,13 @@ namespace Spring.Objects.Factory.Support { if (log.IsDebugEnabled) { - log.Debug("Invoking IObjectPostProcessors before initialization of object '" + name + "'"); + log.Debug($"Invoking IObjectPostProcessors before initialization of object '{name}'"); } object result = instance; - for (var i = 0; i < ObjectPostProcessors.Count; i++) + for (var i = 0; i < objectPostProcessors.Count; i++) { - IObjectPostProcessor objectProcessor = ObjectPostProcessors[i]; + IObjectPostProcessor objectProcessor = objectPostProcessors[i]; result = objectProcessor.PostProcessBeforeInitialization(result, name); if (result == null) { @@ -1949,20 +1944,19 @@ namespace Spring.Objects.Factory.Support { if (log.IsDebugEnabled) { - log.Debug("Invoking IObjectPostProcessors after initialization of object '" + name + "'"); + log.Debug($"Invoking IObjectPostProcessors after initialization of object '{name}'"); } object result = instance; - for (var i = 0; i < ObjectPostProcessors.Count; i++) + for (var i = 0; i < objectPostProcessors.Count; i++) { - IObjectPostProcessor objectProcessor = ObjectPostProcessors[i]; + IObjectPostProcessor objectProcessor = objectPostProcessors[i]; result = objectProcessor.PostProcessAfterInitialization(result, name); if (result == null) { throw new ObjectCreationException(name, - string.Format(CultureInfo.InvariantCulture, - "PostProcessAfterInitialization method of IObjectPostProcessor [{0}] " - + " returned null for object [{1}] with name [{2}].", objectProcessor, instance, name)); + $"PostProcessAfterInitialization method of IObjectPostProcessor [{objectProcessor}] " + + $" returned null for object [{instance}] with name [{name}]."); } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectDefinition.cs b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectDefinition.cs index 81a884c9..49a46fc6 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectDefinition.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectDefinition.cs @@ -60,7 +60,7 @@ namespace Spring.Objects.Factory.Support private AutoWiringMode autowireMode = AutoWiringMode.No; private DependencyCheckingMode dependencyCheck = DependencyCheckingMode.None; - private List dependsOn; + internal List dependsOn; private bool autowireCandidate = true; private bool primary; private Dictionary qualifiers; @@ -672,8 +672,8 @@ namespace Spring.Objects.Factory.Support /// /// property. /// - public virtual bool HasConstructorArgumentValues => ConstructorArgumentValues != null - && !ConstructorArgumentValues.Empty; + public bool HasConstructorArgumentValues => constructorArgumentValues != null + && !constructorArgumentValues.Empty; /// /// Resolves the type of the object, resolving it from a specified diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs index 6c1f4bb8..7cfa20e0 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs @@ -1618,7 +1618,7 @@ namespace Spring.Objects.Factory.Support /// /// ObjectPostProcessors to apply in CreateObject /// - private List objectPostProcessors = new List(); + internal List objectPostProcessors = new List(); /// /// String Resolver applied to Autowired value injections @@ -2101,17 +2101,19 @@ namespace Spring.Objects.Factory.Support object monitor = new object(); const int indent = 3; bool hasErrors = false; + var isDebugEnabled = log.IsDebugEnabled; + try { string objectName = TransformedObjectName(name); Interlocked.Increment(ref nestingCount); - if (log.IsDebugEnabled) + if (isDebugEnabled) { log.Debug(string.Format("{2}GetObjectInternal: obtaining instance for name {0} => canonical name {1}", name, objectName, new string(' ', nestingCount * indent))); } - object instance = null; + object instance; // those are cases, where singleton cache can be used if (arguments == null && !suppressConfigure) @@ -2120,7 +2122,7 @@ namespace Spring.Objects.Factory.Support object sharedInstance = GetSingleton(objectName); if (sharedInstance != null) { - if (log.IsDebugEnabled) + if (isDebugEnabled) { if (IsSingletonCurrentlyInCreation(objectName)) { @@ -2138,7 +2140,8 @@ namespace Spring.Objects.Factory.Support } } - if (IsPrototypeCurrentlyInCreation(name)) + var set = prototypesInCreation.Value; + if (set.Contains(name)) { throw new ObjectCurrentlyInCreationException(name); } @@ -2187,14 +2190,17 @@ namespace Spring.Objects.Factory.Support else { // it's a prototype, so create a new instance... - BeforePrototypeCreation(name); + set.Add(name); try { instance = InstantiateObject(name, mergedObjectDefinition, arguments, true, suppressConfigure); } finally { - AfterPrototypeCreation(name); + if (!set.Remove(name)) + { + ThrowNotCurrentlyInCreation(name); + } } } @@ -2241,7 +2247,7 @@ namespace Spring.Objects.Factory.Support } } - if (log.IsDebugEnabled) + if (isDebugEnabled) { log.Debug(string.Format("{1}GetObjectInternal: returning instance for objectname {0}", name, new string(' ', nestingCount * indent))); } @@ -2409,19 +2415,6 @@ namespace Spring.Objects.Factory.Support return IsSingletonCurrentlyInCreation(objectName) || IsPrototypeCurrentlyInCreation(objectName); } - private void BeforePrototypeCreation(string name) - { - prototypesInCreation.Value.Add(name); - } - - private void AfterPrototypeCreation(string name) - { - if (!prototypesInCreation.Value.Remove(name)) - { - ThrowNotCurrentlyInCreation(name); - } - } - private static void ThrowNotCurrentlyInCreation(string name) { throw new InvalidOperationException("Singleton " + name + " isn't currently in creation."); diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/AutowireUtils.cs b/src/Spring/Spring.Core/Objects/Factory/Support/AutowireUtils.cs index b3bf4248..e9ed2185 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/AutowireUtils.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/AutowireUtils.cs @@ -72,11 +72,20 @@ namespace Spring.Objects.Factory.Support /// public static ConstructorInfo[] GetConstructors( IObjectDefinition definition, int minimumArgumentCount) - { + { + var rootObjectDefinition = definition as RootObjectDefinition; + if (minimumArgumentCount == 0 && rootObjectDefinition?.defaultConstructor != null) + { + return rootObjectDefinition.defaultConstructor; + } + const BindingFlags flags = - BindingFlags.Public | BindingFlags.NonPublic - | BindingFlags.Instance | BindingFlags.DeclaredOnly; - ConstructorInfo[] constructors = null; + BindingFlags.Public + | BindingFlags.NonPublic + | BindingFlags.Instance + | BindingFlags.DeclaredOnly; + + ConstructorInfo[] constructors; if (minimumArgumentCount > 0) { MemberInfo[] ctors = definition.ObjectType.FindMembers( @@ -89,6 +98,10 @@ namespace Spring.Objects.Factory.Support else { constructors = definition.ObjectType.GetConstructors(flags); + if (rootObjectDefinition != null) + { + rootObjectDefinition.defaultConstructor = constructors; + } } SortConstructors(constructors); return constructors; @@ -135,10 +148,9 @@ namespace Spring.Objects.Factory.Support Type theParameterType = argTypes[i].ParameterType; if (!ObjectUtils.IsAssignable(theParameterType, args[i])) { - return Int32.MaxValue; + return int.MaxValue; } - if (args[i] != null - && !(args[i].GetType().Equals(theParameterType))) + if (args[i] != null && args[i].GetType() != theParameterType) { Type superType = args[i].GetType().BaseType; while (superType != null) @@ -245,7 +257,7 @@ namespace Spring.Objects.Factory.Support /// public static void SortConstructors(ConstructorInfo[] constructors) { - if (constructors != null && constructors.Length > 0) + if (constructors != null && constructors.Length > 1) { Array.Sort(constructors, ConstructorComparer.Instance); } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/ConstructorResolver.cs b/src/Spring/Spring.Core/Objects/Factory/Support/ConstructorResolver.cs index 86375194..ad41d1d5 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/ConstructorResolver.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/ConstructorResolver.cs @@ -98,7 +98,8 @@ namespace Spring.Objects.Factory.Support if (log.IsDebugEnabled) { - log.Debug(string.Format(CultureInfo.InvariantCulture, "Object '{0}' instantiated via constructor [{1}].", objectName, constructorInstantiationInfo.ConstructorInfo)); + log.Debug( + $"Object '{objectName}' instantiated via constructor [{constructorInstantiationInfo.ConstructorInfo}]."); } return wrapper; @@ -110,20 +111,16 @@ namespace Spring.Objects.Factory.Support /// /// Name of the object. /// The RootObjectDefinition - /// The explicitly chosen ctors. + /// The explicitly chosen ctors. /// The explicit chose ctor args. /// A ConstructorInstantiationInfo containg the specified constructor in the RootObjectDefinition or /// one based on type matching. public ConstructorInstantiationInfo GetConstructorInstantiationInfo( string objectName, RootObjectDefinition rod, - ConstructorInfo[] chosenCtors, + ConstructorInfo[] chosenConstructors, object[] explicitArgs) { - - ObjectWrapper wrapper = new ObjectWrapper(); - - ConstructorInfo constructorToUse = null; object[] argsToUse = null; if (explicitArgs != null) @@ -135,13 +132,13 @@ namespace Spring.Objects.Factory.Support //TODO performance optmization on cached ctors. } - // Need to resolve the constructor. - bool autowiring = (chosenCtors != null || - rod.ResolvedAutowireMode == AutoWiringMode.Constructor); + bool autowiring = chosenConstructors != null || rod.ResolvedAutowireMode == AutoWiringMode.Constructor; ConstructorArgumentValues resolvedValues = null; + ObjectWrapper wrapper = null; + ConstructorInfo constructorToUse = null; - int minNrOfArgs = 0; + int minNrOfArgs; if (explicitArgs != null) { minNrOfArgs = explicitArgs.Length; @@ -150,32 +147,33 @@ namespace Spring.Objects.Factory.Support { ConstructorArgumentValues cargs = rod.ConstructorArgumentValues; resolvedValues = new ConstructorArgumentValues(); + wrapper = new ObjectWrapper(); minNrOfArgs = ResolveConstructorArguments(objectName, rod, wrapper, cargs, resolvedValues); } // Take specified constructors, if any. - ConstructorInfo[] candidates = chosenCtors ?? AutowireUtils.GetConstructors(rod, 0); + ConstructorInfo[] candidates = chosenConstructors ?? AutowireUtils.GetConstructors(rod, 0); AutowireUtils.SortConstructors(candidates); int minTypeDiffWeight = int.MaxValue; for (int i = 0; i < candidates.Length; i++) { ConstructorInfo candidate = candidates[i]; - Type[] paramTypes = ReflectionUtils.GetParameterTypes(candidate.GetParameters()); - if (constructorToUse != null && argsToUse.Length > paramTypes.Length) + var parameters = candidate.GetParameters(); + if (constructorToUse != null && argsToUse.Length > parameters.Length) { // already found greedy constructor that can be satisfied, so // don't look any further, there are only less greedy constructors left... break; } - if (paramTypes.Length < minNrOfArgs) + if (parameters.Length < minNrOfArgs) { throw new ObjectCreationException(rod.ResourceDescription, objectName, - string.Format(CultureInfo.InvariantCulture, - "'{0}' constructor arguments specified but no matching constructor found " - + "in object '{1}' (hint: specify argument indexes, names, or " - + "types to avoid ambiguities).", minNrOfArgs, objectName)); + $"'{minNrOfArgs}' constructor arguments specified but no matching constructor found " + + $"in object '{objectName}' (hint: specify argument indexes, names, or " + + "types to avoid ambiguities)."); } + Type[] paramTypes = ReflectionUtils.GetParameterTypes(parameters); ArgumentsHolder args; if (resolvedValues != null) { @@ -210,12 +208,11 @@ namespace Spring.Objects.Factory.Support else { // Explicit arguments given -> arguments length must match exactly - if (paramTypes.Length != explicitArgs.Length) + if (parameters.Length != explicitArgs.Length) { continue; } - args = new ArgumentsHolder(explicitArgs); - + args = ArgumentsHolder.Create(explicitArgs); } int typeDiffWeight = args.GetTypeDifferenceWeight(paramTypes); // Choose this constructor if it represents the closest match. @@ -225,18 +222,14 @@ namespace Spring.Objects.Factory.Support argsToUse = args.arguments; minTypeDiffWeight = typeDiffWeight; } - } - if (constructorToUse == null) { throw new ObjectCreationException(rod.ResourceDescription, objectName, "Could not resolve matching constructor."); } return new ConstructorInstantiationInfo(constructorToUse, argsToUse); - - } /// @@ -361,7 +354,7 @@ namespace Spring.Objects.Factory.Support if (log.IsDebugEnabled) { - log.Debug(string.Format(CultureInfo.InvariantCulture, "Object '{0}' instantiated via factory method [{1}].", name, factoryMethodCandidate)); + log.Debug($"Object '{name}' instantiated via factory method [{factoryMethodCandidate}]."); } return wrapper; @@ -371,8 +364,7 @@ namespace Spring.Objects.Factory.Support // if we get here, we didn't match any method... throw new ObjectDefinitionStoreException( - string.Format(CultureInfo.InvariantCulture, "Cannot find matching factory method '{0} on Type [{1}].", definition.FactoryMethodName, - factoryClass)); + $"Cannot find matching factory method '{definition.FactoryMethodName} on Type [{factoryClass}]."); } /// @@ -382,17 +374,32 @@ namespace Spring.Objects.Factory.Support /// When return value is null the out parameter UnsatisfiedDependencyExceptionData will contain /// information for use in throwing a UnsatisfiedDependencyException by the caller. This avoids using /// exceptions for flow control as in the original implementation. - private ArgumentsHolder CreateArgumentArray(string objectName, RootObjectDefinition rod, ConstructorArgumentValues resolvedValues, ObjectWrapper wrapper, Type[] paramTypes, MethodBase methodOrCtorInfo, bool autowiring, out UnsatisfiedDependencyExceptionData unsatisfiedDependencyExceptionData) + private ArgumentsHolder CreateArgumentArray( + string objectName, + RootObjectDefinition rod, + ConstructorArgumentValues resolvedValues, + ObjectWrapper wrapper, + Type[] paramTypes, + MethodBase methodOrCtorInfo, + bool autowiring, + out UnsatisfiedDependencyExceptionData unsatisfiedDependencyExceptionData) { - string methodType = (methodOrCtorInfo is ConstructorInfo) ? "constructor" : "factory method"; + string GetMethodType() + { + return methodOrCtorInfo is ConstructorInfo ? "constructor" : "factory method"; + } + unsatisfiedDependencyExceptionData = null; + if (paramTypes.Length == 0) + { + return ArgumentsHolder.Empty; + } ArgumentsHolder args = new ArgumentsHolder(paramTypes.Length); var usedValueHolders = new HybridSet(); List autowiredObjectNames = null; - bool resolveNecessary = false; - ParameterInfo[] argTypes = methodOrCtorInfo.GetParameters(); + ParameterInfo[] argTypes = methodOrCtorInfo.GetParameters(); for (int paramIndex = 0; paramIndex < paramTypes.Length; paramIndex++) { @@ -412,7 +419,6 @@ namespace Spring.Objects.Factory.Support valueHolder = resolvedValues.GetArgumentValue(paramIndex, paramType, usedValueHolders); } - if (valueHolder == null && !autowiring) { valueHolder = resolvedValues.GetGenericArgumentValue(null, usedValueHolders); @@ -434,11 +440,8 @@ namespace Spring.Objects.Factory.Support } catch (TypeMismatchException ex) { - //To avoid using exceptions for flow control, this is not a cost in Java as stack trace is lazily created. - string errorMessage = String.Format(CultureInfo.InvariantCulture, - "Could not convert {0} argument value [{1}] to required type [{2}] : {3}", - methodType, valueHolder.Value, - paramType, ex.Message); + // to avoid using exceptions for flow control, this is not a cost in Java as stack trace is lazily created. + string errorMessage = $"Could not convert {GetMethodType()} argument value [{valueHolder.Value}] to required type [{paramType}] : {ex.Message}"; unsatisfiedDependencyExceptionData = new UnsatisfiedDependencyExceptionData(paramIndex, paramType, errorMessage); return null; } @@ -449,10 +452,8 @@ namespace Spring.Objects.Factory.Support // have to fail creating an argument array for the given constructor. if (!autowiring) { - string errorMessage = String.Format(CultureInfo.InvariantCulture, - "Ambiguous {0} argument types - " + - "Did you specify the correct object references as {0} arguments?", - methodType); + string errorMessage = $"Ambiguous {GetMethodType()} argument types - " + + $"Did you specify the correct object references as {GetMethodType()} arguments?"; unsatisfiedDependencyExceptionData = new UnsatisfiedDependencyExceptionData(paramIndex, paramType, errorMessage); return null; @@ -465,7 +466,6 @@ namespace Spring.Objects.Factory.Support args.rawArguments[paramIndex] = autowiredArgument; args.arguments[paramIndex] = autowiredArgument; args.preparedArguments[paramIndex] = new AutowiredArgumentMarker(); - resolveNecessary = true; } catch (ObjectsException ex) { @@ -473,7 +473,6 @@ namespace Spring.Objects.Factory.Support return null; } - } } @@ -483,13 +482,11 @@ namespace Spring.Objects.Factory.Support { string autowiredObjectName = autowiredObjectNames[i]; log.Debug( - $"Autowiring by type from object name '{objectName}' via {methodType} to object named '{autowiredObjectName}'"); + $"Autowiring by type from object name '{objectName}' via {GetMethodType()} to object named '{autowiredObjectName}'"); } } - return args; - } private class AutowiredArgumentMarker @@ -545,50 +542,62 @@ namespace Spring.Objects.Factory.Support // ObjectDefinitionValueResolver valueResolver = new ObjectDefinitionValueResolver(objectFactory); int minNrOfArgs = cargs.ArgumentCount; - foreach (KeyValuePair entry in cargs.IndexedArgumentValues) + if (cargs._indexedArgumentValues != null) { - int index = Convert.ToInt32(entry.Key); - if (index < 0) + foreach (var entry in cargs._indexedArgumentValues) { - throw new ObjectCreationException(definition.ResourceDescription, objectName, - "Invalid constructor agrument index: " + index); + int index = entry.Key; + if (index < 0) + { + throw new ObjectCreationException( + definition.ResourceDescription, + objectName, + $"Invalid constructor argument index: {index}"); + } + + if (index > minNrOfArgs) + { + minNrOfArgs = index + 1; + } + + ConstructorArgumentValues.ValueHolder valueHolder = entry.Value; + string argName = "constructor argument with index " + index; + object resolvedValue = valueResolver.ResolveValueIfNecessary(objectName, definition, argName, valueHolder.Value); + resolvedValues.AddIndexedArgumentValue(index, resolvedValue, + StringUtils.HasText(valueHolder.Type) + ? TypeResolutionUtils.ResolveType(valueHolder.Type).AssemblyQualifiedName + : null); } - if (index > minNrOfArgs) - { - minNrOfArgs = index + 1; - } - ConstructorArgumentValues.ValueHolder valueHolder = entry.Value; - string argName = "constructor argument with index " + index; - object resolvedValue = - valueResolver.ResolveValueIfNecessary(objectName, definition, argName, valueHolder.Value); - resolvedValues.AddIndexedArgumentValue(index, resolvedValue, - StringUtils.HasText(valueHolder.Type) - ? TypeResolutionUtils.ResolveType(valueHolder.Type). - AssemblyQualifiedName - : null); } - foreach (ConstructorArgumentValues.ValueHolder valueHolder in definition.ConstructorArgumentValues.GenericArgumentValues) + if (definition.ConstructorArgumentValues._genericArgumentValues != null) { - string argName = "constructor argument"; - object resolvedValue = - valueResolver.ResolveValueIfNecessary(objectName, definition, argName, valueHolder.Value); - resolvedValues.AddGenericArgumentValue(resolvedValue, - StringUtils.HasText(valueHolder.Type) - ? TypeResolutionUtils.ResolveType(valueHolder.Type). - AssemblyQualifiedName - : null); + const string argName = "constructor argument"; + for (var i = 0; i < definition.ConstructorArgumentValues._genericArgumentValues.Count; i++) + { + var valueHolder = definition.ConstructorArgumentValues._genericArgumentValues[i]; + object resolvedValue = valueResolver.ResolveValueIfNecessary(objectName, definition, argName, valueHolder.Value); + + resolvedValues.AddGenericArgumentValue( + resolvedValue, + StringUtils.HasText(valueHolder.Type) + ? TypeResolutionUtils.ResolveType(valueHolder.Type).AssemblyQualifiedName + : null); + } } - foreach (KeyValuePair namedArgumentEntry in definition.ConstructorArgumentValues.NamedArgumentValues) + + if (definition.ConstructorArgumentValues._namedArgumentValues != null) { - string argumentName = namedArgumentEntry.Key; - string syntheticArgumentName = "constructor argument with name " + argumentName; - ConstructorArgumentValues.ValueHolder valueHolder = - (ConstructorArgumentValues.ValueHolder)namedArgumentEntry.Value; - object resolvedValue = - valueResolver.ResolveValueIfNecessary(objectName, definition, syntheticArgumentName, valueHolder.Value); - resolvedValues.AddNamedArgumentValue(argumentName, resolvedValue); + foreach (var entry in definition.ConstructorArgumentValues._namedArgumentValues) + { + string argumentName = entry.Key; + string syntheticArgumentName = "constructor argument with name " + argumentName; + ConstructorArgumentValues.ValueHolder valueHolder = entry.Value; + object resolvedValue = valueResolver.ResolveValueIfNecessary(objectName, definition, syntheticArgumentName, valueHolder.Value); + resolvedValues.AddNamedArgumentValue(argumentName, resolvedValue); + } } + return minNrOfArgs; } @@ -626,25 +635,44 @@ namespace Spring.Objects.Factory.Support private class ArgumentsHolder { + internal static readonly ArgumentsHolder Empty = new ArgumentsHolder(0); + public readonly object[] rawArguments; public readonly object[] arguments; public readonly object[] preparedArguments; - public ArgumentsHolder(int size) { - rawArguments = new object[size]; - arguments = new object[size]; - preparedArguments = new object[size]; + rawArguments = size == 0 ? ObjectUtils.EmptyObjects : new object[size]; + arguments = size == 0 ? ObjectUtils.EmptyObjects : new object[size]; + preparedArguments = size == 0 ? ObjectUtils.EmptyObjects : new object[size]; } - public ArgumentsHolder(object[] args) + private ArgumentsHolder(object[] args) { rawArguments = args; arguments = args; preparedArguments = args; } + public static ArgumentsHolder Create(object[] args) + { + if (args.Length == 0) + { + return Empty; + } + return new ArgumentsHolder(args); + } + + public static ArgumentsHolder Create(int size) + { + if (size == 0) + { + return Empty; + } + return new ArgumentsHolder(size); + } + public int GetTypeDifferenceWeight(Type[] paramTypes) { // If valid arguments found, determine type difference weight. diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionValueResolver.cs b/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionValueResolver.cs index 4754b88d..72fe6402 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionValueResolver.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionValueResolver.cs @@ -136,31 +136,27 @@ namespace Spring.Objects.Factory.Support { resolvedValue = argumentValue; } - else if (argumentValue is ICustomValueReferenceHolder) + else if (argumentValue is ICustomValueReferenceHolder referenceHolder) { - resolvedValue = ((ICustomValueReferenceHolder) argumentValue).Resolve(objectFactory, name, definition, argumentName, argumentValue); + resolvedValue = referenceHolder.Resolve(objectFactory, name, definition, argumentName, referenceHolder); } - else if (argumentValue is ObjectDefinitionHolder) + else if (argumentValue is ObjectDefinitionHolder holder) { // contains an IObjectDefinition with name and aliases... - ObjectDefinitionHolder holder = (ObjectDefinitionHolder)argumentValue; resolvedValue = ResolveInnerObjectDefinition(name, holder.ObjectName, argumentName, holder.ObjectDefinition, definition.IsSingleton); } - else if (argumentValue is IObjectDefinition) + else if (argumentValue is IObjectDefinition def) { // resolve plain IObjectDefinition, without contained name: use dummy name... - IObjectDefinition def = (IObjectDefinition)argumentValue; resolvedValue = ResolveInnerObjectDefinition(name, "(inner object)", argumentName, def, definition.IsSingleton); } - else if (argumentValue is RuntimeObjectReference) + else if (argumentValue is RuntimeObjectReference reference) { - RuntimeObjectReference roref = (RuntimeObjectReference)argumentValue; - resolvedValue = ResolveReference(definition, name, argumentName, roref); + resolvedValue = ResolveReference(definition, name, argumentName, reference); } - else if (argumentValue is ExpressionHolder) + else if (argumentValue is ExpressionHolder expHolder) { - ExpressionHolder expHolder = (ExpressionHolder)argumentValue; object context = null; IDictionary variables = null; @@ -176,13 +172,12 @@ namespace Spring.Objects.Factory.Support ? null : ResolveValueIfNecessary(name, definition, "Variables", variablesProperty.Value)); - if (vars is IDictionary) + if (vars is IDictionary objects) { - variables = (IDictionary)vars; + variables = objects; } - if (vars is IDictionary) + if (vars is IDictionary temp) { - IDictionary temp = (IDictionary) vars; variables = new Dictionary(temp.Count); foreach (DictionaryEntry entry in temp) { @@ -191,24 +186,29 @@ namespace Spring.Objects.Factory.Support } else { - if (vars != null) throw new ArgumentException("'Variables' must resolve to an IDictionary"); + if (vars != null) + { + throw new ArgumentException("'Variables' must resolve to an IDictionary"); + } } } - if (variables == null) variables = new Dictionary(StringComparer.OrdinalIgnoreCase); + if (variables == null) + { + variables = new Dictionary(StringComparer.OrdinalIgnoreCase); + } // add 'this' objectfactory reference to variables variables.Add(Expression.ReservedVariableNames.CurrentObjectFactory, objectFactory); resolvedValue = expHolder.Expression.GetValue(context, variables); } - else if (argumentValue is IManagedCollection) + else if (argumentValue is IManagedCollection collection) { resolvedValue = - ((IManagedCollection)argumentValue).Resolve(name, definition, argumentName, ResolveValueIfNecessary); + collection.Resolve(name, definition, argumentName, ResolveValueIfNecessary); } - else if (argumentValue is TypedStringValue) + else if (argumentValue is TypedStringValue tsv) { - TypedStringValue tsv = (TypedStringValue)argumentValue; try { Type resolvedTargetType = ResolveTargetType(tsv); diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/RootObjectDefinition.cs b/src/Spring/Spring.Core/Objects/Factory/Support/RootObjectDefinition.cs index ba63e5a6..f81f4fea 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/RootObjectDefinition.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/RootObjectDefinition.cs @@ -21,6 +21,7 @@ #region Imports using System; +using System.Reflection; using System.Runtime.Serialization; using Spring.Objects.Factory.Config; @@ -62,6 +63,8 @@ namespace Spring.Objects.Factory.Support [Serializable] public class RootObjectDefinition : AbstractObjectDefinition { + internal ConstructorInfo[] defaultConstructor; + /// /// Creates a new instance of the /// class. diff --git a/src/Spring/Spring.Core/Objects/ObjectWrapper.cs b/src/Spring/Spring.Core/Objects/ObjectWrapper.cs index b34299ab..e8a6a520 100644 --- a/src/Spring/Spring.Core/Objects/ObjectWrapper.cs +++ b/src/Spring/Spring.Core/Objects/ObjectWrapper.cs @@ -1,7 +1,5 @@ -#region License - /* - * Copyright © 2002-2011 the original author or authors. + * Copyright © 2002-2011 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. @@ -16,8 +14,6 @@ * limitations under the License. */ -#endregion - using System; using System.Collections.Generic; using System.ComponentModel; @@ -58,21 +54,9 @@ namespace Spring.Objects { private static readonly ILog Log = LogManager.GetLogger(typeof(ObjectWrapper)); - #region Fields - /// The wrapped object. private object wrappedObject; - /// - /// The ILog instance for this class. We'll create a lot of these objects, - /// so we don't want a new instance every time. - /// - private static readonly ILog log = LogManager.GetLogger(typeof(ObjectWrapper)); - - #endregion - - #region Constructor (s) / Destructor - /// /// Creates a new instance of the class. /// @@ -132,10 +116,6 @@ namespace Spring.Objects } } - #endregion - - #region Properties - /// /// The object wrapped by this . /// @@ -145,14 +125,14 @@ namespace Spring.Objects /// public object WrappedInstance { - get { return wrappedObject; } + get => wrappedObject; set { if (value == null) { throw new FatalObjectException("Wraped instance cannot be null."); } - this.wrappedObject = value; + wrappedObject = value; } } @@ -172,14 +152,7 @@ namespace Spring.Objects /// If the property /// is . /// - public Type WrappedType - { - get { return WrappedInstance.GetType(); } - } - - #endregion - - #region Methods + public Type WrappedType => WrappedInstance.GetType(); /// Gets the value of a property. /// @@ -218,7 +191,7 @@ namespace Spring.Objects /// public virtual object GetPropertyValue(IExpression propertyExpression) { - return propertyExpression.GetValue(this.wrappedObject); + return propertyExpression.GetValue(wrappedObject); } /// @@ -261,7 +234,7 @@ namespace Spring.Objects /// The new value. public virtual void SetPropertyValue(IExpression propertyExpression, object val) { - propertyExpression.SetValue(this.wrappedObject, val); + propertyExpression.SetValue(wrappedObject, val); } /// @@ -331,7 +304,7 @@ namespace Spring.Objects /// public virtual void SetPropertyValues(IPropertyValues propertyValues, bool ignoreUnknown) { - List propertyAccessExceptions = new List(); + var propertyAccessExceptions = new List(); foreach (PropertyValue pv in propertyValues) { try @@ -342,7 +315,7 @@ namespace Spring.Objects { if (!ignoreUnknown) { - Log.Error(string.Format("Failed setting property '{0}'", pv.Name), ex); + Log.Error($"Failed setting property '{pv.Name}'", ex); throw; } } @@ -350,23 +323,23 @@ namespace Spring.Objects { if (!ignoreUnknown) { - Log.Error(string.Format("Failed setting property '{0}'", pv.Name), ex); + Log.Error($"Failed setting property '{pv.Name}'", ex); throw; } } catch (TypeMismatchException ex) // otherwise, just ignore it and continue... { - Log.Error(string.Format("Failed setting property '{0}'", pv.Name), ex); + Log.Error($"Failed setting property '{pv.Name}'", ex); propertyAccessExceptions.Add(ex); } catch (MethodInvocationException ex) { - Log.Error(string.Format("Failed setting property '{0}'", pv.Name), ex); + Log.Error($"Failed setting property '{pv.Name}'", ex); propertyAccessExceptions.Add(ex); } catch (Exception ex) { - Log.Error(string.Format("Failed setting property '{0}' on instance of type '{1}'", pv.Name, this.WrappedType.FullName), ex); + Log.Error($"Failed setting property '{pv.Name}' on instance of type '{WrappedType.FullName}'", ex); throw; } } @@ -386,7 +359,7 @@ namespace Spring.Objects /// If cannot be determined. public PropertyInfo GetPropertyInfo(string propertyName) { - return (PropertyInfo) this.GetPropertyOrFieldInfo(propertyName); + return (PropertyInfo) GetPropertyOrFieldInfo(propertyName); } /// @@ -400,7 +373,7 @@ namespace Spring.Objects /// public Type GetPropertyType(string propertyName) { - MemberInfo memberInfo = this.GetPropertyOrFieldInfo(propertyName); + var memberInfo = GetPropertyOrFieldInfo(propertyName); switch(memberInfo.MemberType) { case MemberTypes.Property: @@ -408,7 +381,7 @@ namespace Spring.Objects case MemberTypes.Field: return ((FieldInfo) memberInfo).FieldType; default: - throw new FatalObjectException("'" + propertyName + "' is not a valid property expression."); + throw new FatalObjectException($"'{propertyName}' is not a valid property expression."); } } @@ -428,30 +401,30 @@ namespace Spring.Objects try { IExpression propertyExpression = GetPropertyExpression(propertyOrFieldName); - if(propertyExpression is PropertyOrFieldNode) + if(propertyExpression is PropertyOrFieldNode propertyOrFieldNode) { - return ((PropertyOrFieldNode)propertyExpression).GetMemberInfo(this.wrappedObject); + return propertyOrFieldNode.GetMemberInfo(wrappedObject); } - else if(propertyExpression is IndexerNode) + + if(propertyExpression is IndexerNode indexerNode) { - return ((IndexerNode)propertyExpression).GetPropertyInfo(this.wrappedObject, null); + return indexerNode.GetPropertyInfo(wrappedObject, null); } - else if(propertyExpression is Expression) + + if(propertyExpression is Expression expression) { - return ((Expression)propertyExpression).GetPropertyInfo(this.wrappedObject, null); - } - else - { - throw new FatalObjectException("'" + propertyOrFieldName + "' is not a valid property or field expression."); + return expression.GetPropertyInfo(wrappedObject, null); } + + throw new FatalObjectException($"'{propertyOrFieldName}' is not a valid property or field expression."); } catch(RecognitionException e) { - throw new FatalObjectException("Failed to parse property or field name '" + propertyOrFieldName + "'.", e); + throw new FatalObjectException($"Failed to parse property or field name '{propertyOrFieldName}'.", e); } catch(TokenStreamRecognitionException e) { - throw new FatalObjectException("Failed to parse property or field name '" + propertyOrFieldName + "'.", e); + throw new FatalObjectException($"Failed to parse property or field name '{propertyOrFieldName}'.", e); } } @@ -470,10 +443,7 @@ namespace Spring.Objects /// /// Return the collection of property descriptors. /// - public PropertyDescriptorCollection PropertyDescriptors - { - get { return TypeDescriptor.GetProperties(WrappedInstance); } - } + public PropertyDescriptorCollection PropertyDescriptors => TypeDescriptor.GetProperties(WrappedInstance); /// /// This method is expensive! Only call for diagnostics and debugging reasons, @@ -499,14 +469,12 @@ namespace Spring.Objects } catch (Exception ex) { - sb.Append("Exception encountered: ").Append(ex.ToString()); + sb.Append("Exception encountered: ").Append(ex); } return sb.ToString(); } - #endregion - - #region Helper methods + private static readonly char[] propertyCharCheckArray = { '.', '[', '(', ' ', '{' }; /// /// Attempts to parse property expression first and falls back to full expression @@ -516,8 +484,8 @@ namespace Spring.Objects /// Parsed proeprty expression. internal static IExpression GetPropertyExpression(string propertyName) { - IExpression propertyExpression = null; - if (propertyName.IndexOfAny(new char[] { '.', '[', '(', ' ', '{' }) < 0) + IExpression propertyExpression; + if (propertyName.IndexOfAny(propertyCharCheckArray) < 0) { try { @@ -535,7 +503,5 @@ namespace Spring.Objects return propertyExpression; } - - #endregion } } \ No newline at end of file diff --git a/src/Spring/Spring.Core/Util/AssertUtils.cs b/src/Spring/Spring.Core/Util/AssertUtils.cs index d7aa49cb..b161cb0a 100644 --- a/src/Spring/Spring.Core/Util/AssertUtils.cs +++ b/src/Spring/Spring.Core/Util/AssertUtils.cs @@ -21,6 +21,7 @@ using System; using System.Collections; using System.Reflection; +using System.Runtime.CompilerServices; using System.Runtime.Remoting; namespace Spring.Util @@ -129,6 +130,7 @@ namespace Spring.Util /// /// If the supplied is . /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ArgumentNotNull(object argument, string name) { if (argument == null) @@ -150,6 +152,7 @@ namespace Spring.Util /// /// If the supplied is . /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ArgumentNotNull(object argument, string name, string message) { if (argument == null) diff --git a/src/Spring/Spring.Core/Util/ReflectionUtils.cs b/src/Spring/Spring.Core/Util/ReflectionUtils.cs index f0d06b6d..9c86cdbe 100644 --- a/src/Spring/Spring.Core/Util/ReflectionUtils.cs +++ b/src/Spring/Spring.Core/Util/ReflectionUtils.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2011 the original author or authors. + * Copyright © 2002-2011 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. @@ -44,6 +44,8 @@ namespace Spring.Util /// Bruno Baia (.NET) public sealed class ReflectionUtils { + internal static Type[] EmptyTypes = new Type[0]; + /// /// Convenience value that will /// match all private and public, static and instance members on a class @@ -259,8 +261,14 @@ namespace Spring.Util public static Type[] GetParameterTypes(ParameterInfo[] args) { AssertUtils.ArgumentNotNull(args, "args"); - Type[] types = new Type[args.Length]; - for (int i = 0; i < args.Length; i++) + + if (args.Length == 0) + { + return EmptyTypes; + } + + var types = new Type[args.Length]; + for (int i = 0; i < (uint) args.Length; i++) { types[i] = args[i].ParameterType; } diff --git a/test/Spring/Spring.Benchmark/Spring.Benchmark.csproj b/test/Spring/Spring.Benchmark/Spring.Benchmark.csproj index d394036b..adf52389 100644 --- a/test/Spring/Spring.Benchmark/Spring.Benchmark.csproj +++ b/test/Spring/Spring.Benchmark/Spring.Benchmark.csproj @@ -7,7 +7,7 @@ - +