#164 tweak object instantiation hot paths
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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}].");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.");
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BenchmarkDotNet" Version="0.11.1" />
|
||||
<PackageReference Include="BenchmarkDotNet" Version="0.11.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user