Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using System.Linq.Expressions;
using System.Numerics.Hashing;
using System.Reflection;
using System.Threading;

namespace System.Composition.TypedParts.Discovery
{
Expand All @@ -31,6 +32,7 @@ internal sealed class DiscoveredPart

// Lazily initialised among potentially many exports
private ConstructorInfo _constructor;
private ParameterInfo[] _constructorParameters;
private CompositeActivator _partActivator;

private static readonly IDictionary<string, object> s_noMetadata = new Dictionary<string, object>();
Expand Down Expand Up @@ -112,7 +114,12 @@ private IEnumerable<CompositionDependency> GetPartActivatorDependencies(Dependen
}
}

var cps = _constructor.GetParameters();
// Use LazyInitializer to ensure GetParameters() is called at most once per
// DiscoveredPart instance and the result is safely published to all threads.
// On some runtimes (e.g. Mono on ARM), concurrent calls to GetParameters()
// on the same ConstructorInfo can return different ParameterInfo instances
// due to lazy initialization, causing lookup failures in GetActivator.
var cps = LazyInitializer.EnsureInitialized(ref _constructorParameters, () => _constructor.GetParameters());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is going to allocate a new delegate on every call, regardless of whether _constructorParameters is initialized or not.

Same for the similar change below.


for (var i = 0; i < cps.Length; ++i)
{
Expand Down Expand Up @@ -168,7 +175,7 @@ public CompositeActivator GetActivator(IEnumerable<CompositionDependency> depend
var contextParam = Expression.Parameter(typeof(LifetimeContext), "cc");
var operationParm = Expression.Parameter(typeof(CompositionOperation), "op");

var cps = _constructor.GetParameters();
var cps = LazyInitializer.EnsureInitialized(ref _constructorParameters, _constructor.GetParameters);
Expression[] paramActivatorCalls = new Expression[cps.Length];

var partActivatorDependencies = dependencies
Expand Down
Loading