#164 tweak object instantiation hot paths

This commit is contained in:
Marko Lahma
2018-10-28 18:29:50 +02:00
parent d834297b2b
commit ada35f07f4
14 changed files with 311 additions and 301 deletions

View File

@@ -42,13 +42,13 @@ namespace Spring.Objects.Factory.Config
private static readonly CultureInfo enUSCultureInfo = new CultureInfo("en-US", false);
private static readonly IReadOnlyDictionary<int, ValueHolder> _emptyIndexedArgumentValues = new Dictionary<int, ValueHolder>();
private Dictionary<int, ValueHolder> _indexedArgumentValues = null;
internal Dictionary<int, ValueHolder> _indexedArgumentValues = null;
private static readonly IReadOnlyList<ValueHolder> _emptyGenericArgumentValues = new List<ValueHolder>();
private List<ValueHolder> _genericArgumentValues = null;
internal List<ValueHolder> _genericArgumentValues = null;
private static readonly IReadOnlyDictionary<string, object> _emptyNamedArgumentValues = new Dictionary<string, object>();
private Dictionary<string, object> _namedArgumentValues = null;
private static readonly IReadOnlyDictionary<string, ValueHolder> _emptyNamedArgumentValues = new Dictionary<string, ValueHolder>();
internal Dictionary<string, ValueHolder> _namedArgumentValues = null;
/// <summary>
/// Can be used as an argument filler for the
@@ -101,7 +101,7 @@ namespace Spring.Objects.Factory.Config
/// <see cref="Spring.Objects.Factory.Config.ConstructorArgumentValues.ValueHolder"/>s
/// as values.
/// </returns>
public IReadOnlyDictionary<string, object> NamedArgumentValues => _namedArgumentValues ?? _emptyNamedArgumentValues;
public IReadOnlyDictionary<string, ValueHolder> NamedArgumentValues => _namedArgumentValues ?? _emptyNamedArgumentValues;
/// <summary>
/// Return the set of generic argument values.
@@ -115,19 +115,54 @@ namespace Spring.Objects.Factory.Config
/// <summary>
/// Return the number of arguments held in this instance.
/// </summary>
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;
}
}
/// <summary>
/// Returns true if this holder does not contain any argument values,
/// neither indexed ones nor generic ones.
/// </summary>
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;
}
/// <summary>
return true;
}
}
/// <summary>
/// Copy all given argument values into this object.
/// </summary>
/// <param name="other">
@@ -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<int, ValueHolder>();
}
private Dictionary<string, object> GetAndInitializeNamedArgumentValuesIfNeeded()
private Dictionary<string, ValueHolder> GetAndInitializeNamedArgumentValuesIfNeeded()
{
return _namedArgumentValues = _namedArgumentValues ?? new Dictionary<string, object>();
return _namedArgumentValues = _namedArgumentValues ?? new Dictionary<string, ValueHolder>();
}
private List<ValueHolder> 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;
}

View File

@@ -1,7 +1,5 @@
#region License
/*
* Copyright <EFBFBD> 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
{
/// <summary>
@@ -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
/// <summary>
/// Creates a new instance of the
/// <see cref="Spring.Objects.Factory.Config.ExpressionHolder"/>
@@ -59,11 +45,7 @@ namespace Spring.Objects.Factory.Config
this.expression = Spring.Expressions.Expression.Parse(expression);
}
#endregion
#region Properties
/// <summary>
/// <summary>
/// Gets or sets the expression string. Setting the expression string will cause
/// the expression to be parsed.
/// </summary>
@@ -90,20 +72,13 @@ namespace Spring.Objects.Factory.Config
set { properties = value; }
}
#endregion
#region Methods
/// <summary>
/// Returns a string representation of this instance.
/// </summary>
/// <returns>A string representation of this instance.</returns>
public override string ToString()
{
return string.Format(
CultureInfo.InvariantCulture, "<{0}>", expressionString);
return $"<{expressionString}>";
}
#endregion
}
}

View File

@@ -145,7 +145,7 @@ namespace Spring.Objects.Factory.Config
/// specified IVariableSource.
/// </summary>
/// <param name="nav">The named argument values.</param>
protected virtual void VisitNamedArgumentValues(IReadOnlyDictionary<string, object> nav)
protected virtual void VisitNamedArgumentValues(IReadOnlyDictionary<string, ConstructorArgumentValues.ValueHolder> nav)
{
foreach (ConstructorArgumentValues.ValueHolder valueHolder in nav.Values)
{

View File

@@ -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}].");
}
}

View File

@@ -60,7 +60,7 @@ namespace Spring.Objects.Factory.Support
private AutoWiringMode autowireMode = AutoWiringMode.No;
private DependencyCheckingMode dependencyCheck = DependencyCheckingMode.None;
private List<string> dependsOn;
internal List<string> dependsOn;
private bool autowireCandidate = true;
private bool primary;
private Dictionary<string, AutowireCandidateQualifier> qualifiers;
@@ -672,8 +672,8 @@ namespace Spring.Objects.Factory.Support
/// <see cref="Spring.Objects.Factory.Support.AbstractObjectDefinition.ConstructorArgumentValues"/>
/// property.
/// </value>
public virtual bool HasConstructorArgumentValues => ConstructorArgumentValues != null
&& !ConstructorArgumentValues.Empty;
public bool HasConstructorArgumentValues => constructorArgumentValues != null
&& !constructorArgumentValues.Empty;
/// <summary>
/// Resolves the type of the object, resolving it from a specified

View File

@@ -1618,7 +1618,7 @@ namespace Spring.Objects.Factory.Support
/// <summary>
/// ObjectPostProcessors to apply in CreateObject
/// </summary>
private List<IObjectPostProcessor> objectPostProcessors = new List<IObjectPostProcessor>();
internal List<IObjectPostProcessor> objectPostProcessors = new List<IObjectPostProcessor>();
/// <summary>
/// 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.");

View File

@@ -72,11 +72,20 @@ namespace Spring.Objects.Factory.Support
/// </returns>
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
/// </param>
public static void SortConstructors(ConstructorInfo[] constructors)
{
if (constructors != null && constructors.Length > 0)
if (constructors != null && constructors.Length > 1)
{
Array.Sort(constructors, ConstructorComparer.Instance);
}

View File

@@ -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
/// </summary>
/// <param name="objectName">Name of the object.</param>
/// <param name="rod">The RootObjectDefinition</param>
/// <param name="chosenCtors">The explicitly chosen ctors.</param>
/// <param name="chosenConstructors">The explicitly chosen ctors.</param>
/// <param name="explicitArgs">The explicit chose ctor args.</param>
/// <returns>A ConstructorInstantiationInfo containg the specified constructor in the RootObjectDefinition or
/// one based on type matching.</returns>
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);
}
/// <summary>
@@ -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}].");
}
/// <summary>
@@ -382,17 +374,32 @@ namespace Spring.Objects.Factory.Support
/// <remarks>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.</remarks>
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<string> 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<int, ConstructorArgumentValues.ValueHolder> 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<string, object> 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.

View File

@@ -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<string, object> variables = null;
@@ -176,13 +172,12 @@ namespace Spring.Objects.Factory.Support
? null
: ResolveValueIfNecessary(name, definition, "Variables",
variablesProperty.Value));
if (vars is IDictionary<string, object>)
if (vars is IDictionary<string, object> objects)
{
variables = (IDictionary<string, object>)vars;
variables = objects;
}
if (vars is IDictionary)
if (vars is IDictionary temp)
{
IDictionary temp = (IDictionary) vars;
variables = new Dictionary<string, object>(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<string, object>(StringComparer.OrdinalIgnoreCase);
if (variables == null)
{
variables = new Dictionary<string, object>(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);

View File

@@ -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;
/// <summary>
/// Creates a new instance of the
/// <see cref="Spring.Objects.Factory.Support.RootObjectDefinition"/> class.

View File

@@ -1,7 +1,5 @@
#region License
/*
* Copyright <EFBFBD> 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
/// <summary>The wrapped object.</summary>
private object wrappedObject;
/// <summary>
/// The ILog instance for this class. We'll create a lot of these objects,
/// so we don't want a new instance every time.
/// </summary>
private static readonly ILog log = LogManager.GetLogger(typeof(ObjectWrapper));
#endregion
#region Constructor (s) / Destructor
/// <summary>
/// Creates a new instance of the <see cref="Spring.Objects.ObjectWrapper"/> class.
/// </summary>
@@ -132,10 +116,6 @@ namespace Spring.Objects
}
}
#endregion
#region Properties
/// <summary>
/// The object wrapped by this <see cref="Spring.Objects.ObjectWrapper"/>.
/// </summary>
@@ -145,14 +125,14 @@ namespace Spring.Objects
/// </exception>
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 <see cref="Spring.Objects.ObjectWrapper.WrappedInstance"/> property
/// is <see lang="null"/>.
/// </exception>
public Type WrappedType
{
get { return WrappedInstance.GetType(); }
}
#endregion
#region Methods
public Type WrappedType => WrappedInstance.GetType();
/// <summary>Gets the value of a property.</summary>
/// <param name="propertyName">
@@ -218,7 +191,7 @@ namespace Spring.Objects
/// </exception>
public virtual object GetPropertyValue(IExpression propertyExpression)
{
return propertyExpression.GetValue(this.wrappedObject);
return propertyExpression.GetValue(wrappedObject);
}
/// <summary>
@@ -261,7 +234,7 @@ namespace Spring.Objects
/// <param name="val">The new value.</param>
public virtual void SetPropertyValue(IExpression propertyExpression, object val)
{
propertyExpression.SetValue(this.wrappedObject, val);
propertyExpression.SetValue(wrappedObject, val);
}
/// <summary>
@@ -331,7 +304,7 @@ namespace Spring.Objects
/// <seealso cref="Spring.Objects.IObjectWrapper.SetPropertyValues(IPropertyValues, bool)"/>
public virtual void SetPropertyValues(IPropertyValues propertyValues, bool ignoreUnknown)
{
List<PropertyAccessException> propertyAccessExceptions = new List<PropertyAccessException>();
var propertyAccessExceptions = new List<PropertyAccessException>();
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
/// <exception cref="FatalObjectException">If <see cref="PropertyInfo"/> cannot be determined.</exception>
public PropertyInfo GetPropertyInfo(string propertyName)
{
return (PropertyInfo) this.GetPropertyOrFieldInfo(propertyName);
return (PropertyInfo) GetPropertyOrFieldInfo(propertyName);
}
/// <summary>
@@ -400,7 +373,7 @@ namespace Spring.Objects
/// </returns>
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
/// <summary>
/// Return the collection of property descriptors.
/// </summary>
public PropertyDescriptorCollection PropertyDescriptors
{
get { return TypeDescriptor.GetProperties(WrappedInstance); }
}
public PropertyDescriptorCollection PropertyDescriptors => TypeDescriptor.GetProperties(WrappedInstance);
/// <summary>
/// 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 = { '.', '[', '(', ' ', '{' };
/// <summary>
/// Attempts to parse property expression first and falls back to full expression
@@ -516,8 +484,8 @@ namespace Spring.Objects
/// <returns>Parsed proeprty expression.</returns>
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
}
}

View File

@@ -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
/// <exception cref="System.ArgumentNullException">
/// If the supplied <paramref name="argument"/> is <see langword="null"/>.
/// </exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ArgumentNotNull(object argument, string name)
{
if (argument == null)
@@ -150,6 +152,7 @@ namespace Spring.Util
/// <exception cref="System.ArgumentNullException">
/// If the supplied <paramref name="argument"/> is <see langword="null"/>.
/// </exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ArgumentNotNull(object argument, string name, string message)
{
if (argument == null)

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright <EFBFBD> 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
/// <author>Bruno Baia (.NET)</author>
public sealed class ReflectionUtils
{
internal static Type[] EmptyTypes = new Type[0];
/// <summary>
/// Convenience <see cref="System.Reflection.BindingFlags"/> 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;
}

View File

@@ -7,7 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.11.1" />
<PackageReference Include="BenchmarkDotNet" Version="0.11.2" />
</ItemGroup>
<ItemGroup>