When a:
* Shared part
* Involved in a circular dependency
* Has more than one export
Then the part should be created only once but is instantiated twice.
Found in version 1.0.16.
Failing test case below.
```
[Shared, Export, Export("named")]
public class TwoExports
{
[Import]
public CircularImporter Importer { get; set; }
}
[Shared, Export]
public class CircularImporter
{
[Import]
public TwoExports TwoExports { get; set; }
}
[TestMethod]
public void SharedPartWithManyExportsInCircularityCreatedOnce()
{
var container = new ContainerConfiguration()
.WithPart<TwoExports>()
.WithPart<CircularImporter>()
.CreateContainer();
var a = container.GetExport<TwoExports>("named");
var b = container.GetExport<TwoExports>();
Assert.AreSame(a, b);
}
```
Comments: Issues is in DiscoveredPart.cs -> DiscoveredPart.GetActivator(). This code is reentrant during activator creation, but doesn't account for that fact. Because of this, it creates two activators for the one part; the activators themselves carry the shared instance, so two activators == two shared instances. The fix is simple - the class just needs to detect when it is already initialising, and return a thunk in that case. The class is single-threaded so no synchronisation is required. First the class needs a Boolean to track whether initialisation of the activator has started: ``` bool _activatorCreationStarted; ``` Then after the initial check in GetActivator(): ``` public CompositeActivator GetActivator(DependencyAccessor definitionAccessor, IEnumerable<CompositionDependency> dependencies) { if (_partActivator != null) return _partActivator; ``` We insert a new condition: ``` if (_activatorCreationStarted) return (c, o) => _partActivator(c, o); _activatorCreationStarted = true; ``` The tests now pass, including the new one in the issue above.
* Shared part
* Involved in a circular dependency
* Has more than one export
Then the part should be created only once but is instantiated twice.
Found in version 1.0.16.
Failing test case below.
```
[Shared, Export, Export("named")]
public class TwoExports
{
[Import]
public CircularImporter Importer { get; set; }
}
[Shared, Export]
public class CircularImporter
{
[Import]
public TwoExports TwoExports { get; set; }
}
[TestMethod]
public void SharedPartWithManyExportsInCircularityCreatedOnce()
{
var container = new ContainerConfiguration()
.WithPart<TwoExports>()
.WithPart<CircularImporter>()
.CreateContainer();
var a = container.GetExport<TwoExports>("named");
var b = container.GetExport<TwoExports>();
Assert.AreSame(a, b);
}
```
Comments: Issues is in DiscoveredPart.cs -> DiscoveredPart.GetActivator(). This code is reentrant during activator creation, but doesn't account for that fact. Because of this, it creates two activators for the one part; the activators themselves carry the shared instance, so two activators == two shared instances. The fix is simple - the class just needs to detect when it is already initialising, and return a thunk in that case. The class is single-threaded so no synchronisation is required. First the class needs a Boolean to track whether initialisation of the activator has started: ``` bool _activatorCreationStarted; ``` Then after the initial check in GetActivator(): ``` public CompositeActivator GetActivator(DependencyAccessor definitionAccessor, IEnumerable<CompositionDependency> dependencies) { if (_partActivator != null) return _partActivator; ``` We insert a new condition: ``` if (_activatorCreationStarted) return (c, o) => _partActivator(c, o); _activatorCreationStarted = true; ``` The tests now pass, including the new one in the issue above.