/// <summary> /// Constructor used for the top-level search /// </summary> /// <param name="type"></param> /// <param name="owner"></param> public TargetTypeSelectorParams(Type type, TargetTypeSelector owner) : this(type) { RootTargets = owner?.RootTargets; // variance always starts off enabled. EnableVariance = true; bool enableContravariance = true; this._forceContravariance = GetInternalContravarianceOverride(Type); if (this._forceContravariance == null) { if (RootTargets != null) { enableContravariance = RootTargets.GetOption( Type, Options.EnableContravariance.Default); } } else { enableContravariance = this._forceContravariance.Value; } if (enableContravariance) { Contravariance = Contravariance.BasesAndInterfaces; } else { Contravariance = Contravariance.None; } }
/// <summary> /// Implementation of <see cref="ICovariantTypeIndex.SelectTypes(Type)"/> /// </summary> /// <param name="type">The type for which a search is to be run.</param> /// <returns>A <see cref="TargetTypeSelector"/></returns> public TargetTypeSelector SelectTypes(Type type) { // this function is complicated by the fact that searching and registering types are asymmetrically parallel. // in theory most applications will register first and then start searching. However, the searching part is parallelised // equally, if registrations continue whilst searching is being performed, then we'd have a problem. So this is written to // ensure that the cached type selectors stay up to date as extra registrations are made. var result = _cachedSearches.GetOrAdd(type, CreateSelector); long resultVersion = Interlocked.Read(ref result.Version); long currentVersion = Interlocked.Read(ref _version); long oldResultVersion = resultVersion; // it's fresh enough if (resultVersion == currentVersion) { return(result.Selector); } while (true) { resultVersion = Interlocked.Read(ref result.Version); currentVersion = Interlocked.Read(ref _version); var newSelector = new TargetTypeSelector(type, _root); result.Selector = newSelector; if (Interlocked.CompareExchange(ref result.Version, currentVersion, resultVersion) == resultVersion) { break; } } return(result.Selector); CachedTargetTypeSelector CreateSelector(Type t) { return(new CachedTargetTypeSelector() { Version = Interlocked.Read(ref _version), Selector = new TargetTypeSelector(t, _root) }); } }