spring-projects/spring-net — pull request #84 by chadsowald (2014-09-18 20:19:10+00:00)
Title: Add equality members to RuntimeObjectReference to fix key-ref merging.

**Overview**
While trying to use the Dictionary merging functionality (documented here: http://www.springframework.net/doc-latest/reference/html/objects.html#d4e1009 ), I found that merging using the key-ref attribute (versus the key attribute) did not work as expected. After debugging, it appears that the reason is that key-ref attributes are internally managed as RuntimeObjectReference objects. This type does not implement equality member overrides and so even though I was referencing the same object in my Spring.NET config, Spring thought I had two separate objects and the child object's dictionary was not merged properly.

**Excepted:**
The child dictionary should be merged with the parent dictionary. Specifically, "Object2" should have a value of null after the merge while "Object1" and "Object3" remain unchanged. So, I expect this:

Furthermore, I would expect this merging to work regardless of if the object used as the key-ref is a singleton or not since that gives more flexibility to the developer.

**Actual:**
The exception below is thrown while the configuration is trying to be resolved.

**Exception:**
This exception is
Spring.Objects.Factory.ObjectCreationException was unhandled by user code
HResult=-2146232832
Message=Error thrown by a dependency of object '...' defined in 'file [...]' : Initialization of object failed : An item with the same key has already been added...
Source=Spring.Core
ObjectName=...
StackTrace:
at Spring.Objects.Factory.Support.ObjectDefinitionValueResolver.ResolveReference(IObjectDefinition definition, String name, String argumentName, RuntimeObjectReference reference)
at Spring.Objects.Factory.Support.ObjectDefinitionValueResolver.ResolvePropertyValue(String name, IObjectDefinition definition, String argumentName, Object argumentValue)
at Spring.Objects.Factory.Support.ObjectDefinitionValueResolver.ResolveValueIfNecessary(String name, IObjectDefinition definition, String argumentName, Object argumentValue)
at Spring.Objects.Factory.Support.AbstractAutowireCapableObjectFactory.ApplyPropertyValues(String name, RootObjectDefinition definition, IObjectWrapper wrapper, IPropertyValues properties)
at Spring.Objects.Factory.Support.AbstractAutowireCapableObjectFactory.PopulateObject(String name, RootObjectDefinition definition, IObjectWrapper wrapper)
at Spring.Objects.Factory.Support.AbstractAutowireCapableObjectFactory.ConfigureObject(String name, RootObjectDefinition definition, IObjectWrapper wrapper)
at Spring.Objects.Factory.Support.AbstractAutowireCapableObjectFactory.InstantiateObject(String name, RootObjectDefinition definition, Object[] arguments, Boolean allowEagerCaching, Boolean suppressConfigure)
at Spring.Objects.Factory.Support.AbstractObjectFactory.CreateAndCacheSingletonInstance(String objectName, RootObjectDefinition objectDefinition, Object[] arguments)
at Spring.Objects.Factory.Support.AbstractObjectFactory.GetObjectInternal(String name, Type requiredType, Object[] arguments, Boolean suppressConfigure)
at Spring.Objects.Factory.Support.AbstractObjectFactory.GetObject(String name)
at Spring.Objects.Factory.Support.DefaultListableObjectFactory.DoGetObjectsOfType(Type type, Boolean includePrototypes, Boolean includeFactoryObjects, IDictionary resultCollector)
at Spring.Objects.Factory.Support.DefaultListableObjectFactory.GetObjects[T](Boolean includePrototypes, Boolean includeFactoryObjects)
at Spring.Context.Support.AbstractApplicationContext.GetObjects[T](Boolean includePrototypes, Boolean includeFactoryObjects)
at Spring.Context.Support.AbstractApplicationContext.RefreshApplicationEventListeners()
at Spring.Context.Support.AbstractApplicationContext.Refresh()
at Spring.Context.Support.XmlApplicationContext..ctor(XmlApplicationContextArgs args)
at Spring.Context.Support.XmlApplicationContext..ctor(String[] configurationLocations)
...
InnerException: System.ArgumentException
HResult=-2147024809
Message=An item with the same key has already been added.
Source=mscorlib
StackTrace:
at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
at System.Collections.Generic.Dictionary`2.System.Collections.IDictionary.Add(Object key, Object value)
at Spring.Objects.Factory.Config.ManagedDictionary.Resolve(String objectName, IObjectDefinition definition, String propertyName, ManagedCollectionElementResolver resolver)
at Spring.Objects.Factory.Support.ObjectDefinitionValueResolver.ResolvePropertyValue(String name, IObjectDefinition definition, String argumentName, Object argumentValue)
at Spring.Objects.Factory.Support.ObjectDefinitionValueResolver.ResolveValueIfNecessary(String name, IObjectDefinition definition, String argumentName, Object argumentValue)
at Spring.Objects.Factory.Support.AbstractAutowireCapableObjectFactory.ApplyPropertyValues(String name, RootObjectDefinition definition, IObjectWrapper wrapper, IPropertyValues properties)
at Spring.Objects.Factory.Support.AbstractAutowireCapableObjectFactory.PopulateObject(String name, RootObjectDefinition definition, IObjectWrapper wrapper)
at Spring.Objects.Factory.Support.AbstractAutowireCapableObjectFactory.ConfigureObject(String name, RootObjectDefinition definition, IObjectWrapper wrapper)
at Spring.Objects.Factory.Support.AbstractAutowireCapableObjectFactory.InstantiateObject(String name, RootObjectDefinition definition, Object[] arguments, Boolean allowEagerCaching, Boolean suppressConfigure)
InnerException:

**Example Spring.NET Config to Reproduce.**
The exception is generated while trying to resolve the "child" object.