internal AutoServiceKind ComputeFinalTypeKind(IActivityMonitor m, IAutoServiceKindComputeFacade kindComputeFacade, ref bool success) { if (!_isComputed) { if (_isComputing) { m.Warn($"Automatic DI type of 'IEnumerable<{EnumeratedType.FullName}> is not decidable: a dependency cycle has been found. It will be considered as the \"worst case\": a non marshallable IsFrontService|IsScoped."); _finalKind = AutoServiceKind.IsFrontService | AutoServiceKind.IsFrontProcessService | AutoServiceKind.IsScoped; } else { // Check that the potential registered IEnumerable AutoServiceKind is compatible with the one of the enumerated interface. var combined = (_itemKind | _enumerabledKind) & ~CKTypeKind.IsMultipleService; var conflict = combined.GetCombinationError(false); if (conflict != null) { m.Error($"Invalid configuration for 'IEnumerable<{EnumeratedType.FullName}>' ({_enumerabledKind}) that contradicts the {EnumeratedType.Name} interface ({_itemKind}): {conflict}."); success = false; } else { _isComputing = true; DoComputeFinalTypeKind(m, kindComputeFacade, combined.ToAutoServiceKind(), ref success); _isComputing = false; } } _isComputed = true; } return(_finalKind); }
public FinalRegistrar( IActivityMonitor monitor, StObjObjectEngineMap engineMap, IAutoServiceKindComputeFacade kindComputeFacade) { _monitor = monitor; _engineMap = engineMap; _infos = new Dictionary <AutoServiceClassInfo, BuildClassInfo>(); _kindComputeFacade = kindComputeFacade; }
internal CKTypeCollectorResult(ISet <Assembly> assemblies, IPocoSupportResult?pocoSupport, RealObjectCollectorResult c, AutoServiceCollectorResult s, IReadOnlyDictionary <Type, TypeAttributesCache?> regularTypes, IAutoServiceKindComputeFacade kindComputeFacade) { PocoSupport = pocoSupport; Assemblies = assemblies; RealObjects = c; AutoServices = s; _regularTypes = regularTypes; KindComputeFacade = kindComputeFacade; }
public IStObjServiceFinalManualMapping?GetFinalMapping( IActivityMonitor m, StObjObjectEngineMap engineMap, IAutoServiceKindComputeFacade kindComputeFacade, ref bool success) { if (!_finalMappingDone) { _finalMappingDone = true; Class.ComputeFinalTypeKind(m, kindComputeFacade, new Stack <AutoServiceClassInfo>(), ref success); if (Assignments.Any()) { _finalMapping = engineMap.CreateServiceFinalManualMapping(this); } } return(_finalMapping); }
bool DoComputeFinalTypeKind(IActivityMonitor m, IAutoServiceKindComputeFacade ctx, AutoServiceKind initial, ref bool success) { Debug.Assert(_rawImpls != null); const AutoServiceKind FrontTypeMask = AutoServiceKind.IsFrontProcessService | AutoServiceKind.IsFrontService; bool isScoped = (initial & AutoServiceKind.IsScoped) != 0; HashSet <Type>?allMarshallableTypes = null; HashSet <Type>?frontMarshallableTypes = null; // If it is [IsMarshallable], the marshaller must handle the marhsalling of any implementations // (this is strange... but who knows?). bool isInterfaceMarshallable = (initial & AutoServiceKind.IsMarshallable) != 0; // If isInterfaceMarshallable is false (regular case), then for this IEnumerable to be marshallable, all its // implementations that are Front services must be marshallable so that it can be resolved as long as its // implementations have been marshalled. // Lets's be optimistic: all implementations that are Front(Process) services (if any) will be marshallable. bool isAutomaticallyMarshallable = true; using (m.OpenTrace($"Computing 'IEnumerable<{EnumeratedType.FullName}>'s final type from {_rawImpls.Count} implementations. Initial: '{initial}'.")) { foreach (var info in _rawImpls) { // RealObject are singleton, are not mashallable and not front process. if (info is RealObjectClassInfo) { continue; } Debug.Assert(info.ServiceClass != null); var impl = info.ServiceClass.MostSpecialized; Debug.Assert(impl != null); // We provide a new empty "cycle detection context" to the class constructors: IEnumerable // of interfaces break potential cycles since they handle their own cycle by resolving to // the "worst" non marshallable IsFrontService|IsScoped. // We consider that if the IEnumerable (or one of its class) cannot be resolved by the DI container, // it's not our problem here. var k = impl.ComputeFinalTypeKind(m, ctx, new Stack <AutoServiceClassInfo>(), ref success); // Check for scope lifetime. if (!isScoped) { if ((k & AutoServiceKind.IsScoped) != 0) { if ((initial & AutoServiceKind.IsSingleton) != 0) { m.Error($"Lifetime error: Type 'IEnumerable<{EnumeratedType.FullName}>' has been registered as a Singleton but implementation '{impl.ClassType}' is Scoped."); success = false; } else { isScoped = true; m.Info($"Type 'IEnumerable<{EnumeratedType.FullName}>' must be Scoped since the implementation '{impl.ClassType}' is Scoped."); } } } // If the implementation is not a front service, we skip it (we don't care of a IsMarshallable only type). if ((k & (AutoServiceKind.IsFrontService | AutoServiceKind.IsFrontProcessService)) == 0) { continue; } var newFinal = _finalKind | (k & AutoServiceKind.IsFrontProcessService | AutoServiceKind.IsFrontService); if (newFinal != _finalKind) { // Upgrades from None, Process to Front... m.Trace($"Type 'IEnumerable<{EnumeratedType.FullName}>' must be {newFinal & FrontTypeMask}, because of (at least) '{impl.ClassType}' implementation."); _finalKind = newFinal; } // If the enumerated Service is marshallable at its level OR it is already known to be NOT automatically marshallable, // we don't have to worry anymore about the subsequent implementations marshalling. if (isInterfaceMarshallable || !isAutomaticallyMarshallable) { continue; } if ((k & AutoServiceKind.IsMarshallable) == 0) { if (success) { m.Warn($"Type 'IEnumerable<{EnumeratedType.FullName}>' is not marshallable and the implementation '{impl.ClassType}' that is a Front service is not marshallable: 'IEnumerable<{EnumeratedType.Name}>' cannot be considered as marshallable."); } isAutomaticallyMarshallable = false; } else { if (allMarshallableTypes == null) { allMarshallableTypes = new HashSet <Type>(); } Debug.Assert(impl.MarshallableTypes != null, "EnsureCtorBinding has been called."); allMarshallableTypes.AddRange(impl.MarshallableTypes); if ((k & AutoServiceKind.IsFrontService) != 0) { if (frontMarshallableTypes == null) { frontMarshallableTypes = new HashSet <Type>(); } Debug.Assert(impl.MarshallableInProcessTypes != null, "EnsureCtorBinding has been called."); frontMarshallableTypes.AddRange(impl.MarshallableInProcessTypes); } } } // Conclude about lifetime. if (!isScoped) { if (success && (initial & AutoServiceKind.IsSingleton) == 0) { m.Info($"Nothing prevents 'IEnumerable<{EnumeratedType.FullName}>' to be considered as a Singleton: this is the most efficient choice."); } _finalKind |= AutoServiceKind.IsSingleton; } else { _finalKind |= AutoServiceKind.IsScoped; } // Conclude about Front aspect. if (isInterfaceMarshallable) { MarshallableTypes = MarshallableInProcessTypes = new[] { EnumeratedType }; Debug.Assert((_finalKind & AutoServiceKind.IsMarshallable) == 0); } else { if (isAutomaticallyMarshallable && allMarshallableTypes != null) { Debug.Assert(allMarshallableTypes.Count > 0); MarshallableTypes = allMarshallableTypes; _finalKind |= AutoServiceKind.IsMarshallable; if (frontMarshallableTypes != null) { MarshallableInProcessTypes = frontMarshallableTypes; } else { MarshallableInProcessTypes = Type.EmptyTypes; } } else { // This service is not a Front service OR it is not automatically marshallable. // We have nothing special to do: the set of Marshallable types is empty (this is not an error). MarshallableTypes = MarshallableInProcessTypes = Type.EmptyTypes; Debug.Assert((_finalKind & AutoServiceKind.IsMarshallable) == 0); } } if (_finalKind != initial) { m.CloseGroup($"Final: {_finalKind}"); } } return(success); }