Пример #1
0
 void CheckStObjProperties(IActivityMonitor monitor, BuildValueCollector valueCollector)
 {
     if (_stObjProperties == null)
     {
         return;
     }
     foreach (StObjProperty p in _stObjProperties)
     {
         if (p.InfoOnType == null || p.InfoOnType.ResolutionSource == PropertyResolutionSource.FromContainerAndThenGeneralization)
         {
             // Check the Type constraint that could potentially hurt one day.
             bool containerHasSetOrMerged = IsOwnContainer && HandleStObjPropertySource(monitor, p, _dContainer !, "Container", true);
             if (Generalization != null)
             {
                 HandleStObjPropertySource(monitor, p, Generalization, "Generalization", !containerHasSetOrMerged);
             }
         }
         else if (p.InfoOnType.ResolutionSource == PropertyResolutionSource.FromGeneralizationAndThenContainer)
         {
             // Check the Type constraint that could potentially hurt one day.
             bool generalizationHasSetOrMerged = Generalization != null && HandleStObjPropertySource(monitor, p, Generalization, "Generalization", true);
             if (IsOwnContainer)
             {
                 HandleStObjPropertySource(monitor, p, _dContainer !, "Container", !generalizationHasSetOrMerged);
             }
         }
         // If the value is missing (it has never been set or has been explicitly "removed"), we have nothing to do.
         // If the type is not constrained, we have nothing to do.
         object v = p.Value;
         if (v != System.Type.Missing)
         {
             bool setIt = p.HasStructuredObjectProperty;
             if (p.Type != typeof(object))
             {
                 if (v == null)
                 {
                     if (p.Type.IsValueType && !(p.Type.IsGenericType && p.Type.GetGenericTypeDefinition() == typeof(Nullable <>)))
                     {
                         monitor.Error($"StObjProperty '{ToString()}.{p.Name}' has been set to null but its type '{p.Type.Name}' is not nullable.");
                         setIt = false;
                     }
                 }
                 else
                 {
                     if (!p.Type.IsAssignableFrom(v.GetType()))
                     {
                         monitor.Error($"StObjProperty '{ToString()}.{p.Name}' is of type '{p.Type.Name}', but a value of type '{v.GetType()}' has been set.");
                         setIt = false;
                     }
                 }
             }
             if (setIt)
             {
                 Debug.Assert(p.InfoOnType != null);
                 AddPreConstructProperty(p.InfoOnType.PropertyInfo, v, valueCollector);
             }
         }
     }
 }
Пример #2
0
 void AddPreConstructProperty(PropertyInfo p, object?o, BuildValueCollector valueCollector)
 {
     if (_preConstruct == null)
     {
         _preConstruct = new List <PropertySetter>();
     }
     _preConstruct.Add(new PropertySetter(p, o, valueCollector));
 }
Пример #3
0
 void AddPostBuildProperty(PropertyInfo p, object o, BuildValueCollector valueCollector)
 {
     Debug.Assert(Specialization == null, "Called on leaf only.");
     if (_leafData.PostBuildProperties == null)
     {
         _leafData.PostBuildProperties = new List <PropertySetter>();
     }
     _leafData.PostBuildProperties.Add(new PropertySetter(p, o, valueCollector));
 }
Пример #4
0
        private void DoCallStObjConstruct(IActivityMonitor monitor, BuildValueCollector valueCollector, IStObjValueResolver?valueResolver, MethodInfo stobjConstruct, IReadOnlyList <MutableParameter> mutableParameters)
        {
            object?[] parameters = new object[mutableParameters.Count];
            int       i          = 0;

            foreach (MutableParameter t in mutableParameters)
            {
                // We inject our "setup monitor" for IActivityMonitor parameter type.
                if (t.IsSetupLogger)
                {
                    t.SetParameterValue(monitor);
                    t.BuilderValueIndex = Int32.MaxValue;
                }
                else
                {
                    MutableItem?resolved = null;
                    if (t.Value == System.Type.Missing)
                    {
                        // Parameter reference have already been resolved as dependencies for graph construction since
                        // no Value has been explicitly set for the parameter.
                        resolved = t.CachedResolvedStObj;
                        if (resolved != null)
                        {
                            Debug.Assert(resolved.InitialObject != System.Type.Missing);
                            t.SetParameterValue(resolved.InitialObject);
                        }
                    }
                    if (valueResolver != null)
                    {
                        valueResolver.ResolveParameterValue(monitor, t);
                    }
                    if (t.Value == System.Type.Missing && !t.IsRealParameterOptional)
                    {
                        if (!t.IsOptional)
                        {
                            // By throwing an exception here, we stop the process and avoid the construction
                            // of an invalid object graph...
                            // This behavior (FailFastOnFailureToResolve) may be an option once. For the moment: log the error.
                            monitor.Fatal($"{t}: Unable to resolve non optional. Attempting to use a default value to continue the setup process in order to detect other errors.");
                        }
                        Debug.Assert(t.Type != null);
                        t.SetParameterValue(t.Type.IsValueType ? Activator.CreateInstance(t.Type) : null);
                    }
                    if (resolved != null && t.Value == resolved.InitialObject)
                    {
                        t.BuilderValueIndex = -(resolved.IndexOrdered + 1);
                    }
                    else
                    {
                        t.BuilderValueIndex = valueCollector.RegisterValue(t.Value);
                    }
                }
                parameters[i++] = t.Value;
            }
            stobjConstruct.Invoke(_leafData.StructuredObject, parameters);
        }
Пример #5
0
 internal PropertySetter(PropertyInfo p, object?o, BuildValueCollector valueCollector)
 {
     Property = p;
     Value    = o;
     if (o is MutableItem)
     {
         IndexValue = -1;
     }
     else
     {
         IndexValue = valueCollector.RegisterValue(o);
     }
 }
 internal void RegisterRemainingDirectPropertiesAsPostBuildProperties(BuildValueCollector valueCollector)
 {
     if (Specialization == null && _leafData.DirectPropertiesToSet != null)
     {
         foreach (var k in _leafData.DirectPropertiesToSet)
         {
             if (k.Value != System.Type.Missing)
             {
                 AddPostBuildProperty(k.Key, k.Value, valueCollector);
             }
         }
         _leafData.DirectPropertiesToSet.Clear();
     }
 }
Пример #7
0
 internal void CallConstruct(IActivityMonitor monitor, BuildValueCollector valueCollector, IStObjValueResolver?valueResolver)
 {
     Debug.Assert(_constructParameterEx != null, "Always allocated.");
     if (_preConstruct != null)
     {
         foreach (var p in _preConstruct)
         {
             SetPropertyValue(monitor, p);
         }
     }
     if (_constructParametersAbove != null)
     {
         foreach (var above in _constructParametersAbove)
         {
             DoCallStObjConstruct(monitor, valueCollector, valueResolver, above.Item1, above.Item2);
         }
     }
     if (RealObjectType.StObjConstruct != null)
     {
         Debug.Assert(_constructParameterEx != null);
         DoCallStObjConstruct(monitor, valueCollector, valueResolver, RealObjectType.StObjConstruct, _constructParameterEx);
     }
 }
Пример #8
0
        /// <summary>
        /// Works on leaf only.
        /// Registers all the DirectProperties values by calling RootGeneralization.AddPreConstructProperty: they will be set right before the call to StObjConstruct of the root of the inheritance chain.
        /// Registers all the InjectObjects (resolves the MutableItem) by calling AddPostBuildProperty on the most specialized leaf: these properties will be set after the whole graph
        /// will be created.
        /// For AmbientProperties, it is slightly more complicated: depending of the property, we will be able to set it before StObjConstruct (like DirectProperties) or only after the whole graph
        /// is created.
        /// - When the AmbientProperty is a mere value (not a StObj), we can call RootGeneralization.AddPreConstructProperty.
        /// - When the AmbientProperty is a StObj, depending on the resolved StObj's TrackAmbientPropertyMode, we call RootGeneralization.AddPreConstructProperty only if
        /// we can be sure that the target StObj (not necessarily its specialization) will be constructed before this object.
        /// This is where the TrackedAmbientPropertyInfo is added to the target and where covariance is handled.
        /// (This is also where, each time I look at this code, I ask myself "wtf...???" :-).)
        /// </summary>
        internal void ResolvePreConstructAndPostBuildProperties(
            IActivityMonitor monitor,
            BuildValueCollector valueCollector,
            IStObjValueResolver?valueResolver)
        {
            Debug.Assert(Specialization == null && _leafData.LeafSpecialization == this, "We are on the ultimate (leaf) Specialization.");
            // Here we AddPreConstructProperty the current direct properties: they will be set on the final object before
            // the call to StObjConstruct.
            // We flush the dictionary and the next calls to SetDirectProperty will be AddPostBuildProperty.
            // This enforces the coherency between build time and runtime.
            if (_leafData.DirectPropertiesToSet != null)
            {
                foreach (var k in _leafData.DirectPropertiesToSet)
                {
                    if (k.Value != System.Type.Missing)
                    {
                        RootGeneralization.AddPreConstructProperty(k.Key, k.Value, valueCollector);
                    }
                }
                _leafData.DirectPropertiesToSet.Clear();
            }
            foreach (var c in _leafData.AllInjectObjects)
            {
                MutableItem?m = c.ResolveToStObj(monitor, EngineMap);
                if (m != null)
                {
                    AddPostBuildProperty(c.InjecttInfo.SettablePropertyInfo, m, valueCollector);
                }
            }

            // Use _ambientPropertiesEx to work on a fixed set of MutableAmbientProperty that
            // correspond to the ones of this object (without the cached ones that may appear at the end of the list).
            foreach (var a in _ambientPropertiesEx)
            {
                Debug.Assert(a.Type != null);
                EnsureCachedAmbientProperty(monitor, a.Type, a.Name, a);
                if (a.Value == System.Type.Missing)
                {
                    if (valueResolver != null)
                    {
                        valueResolver.ResolveExternalPropertyValue(monitor, a);
                    }
                }
                object?value = a.Value;
                if (value == System.Type.Missing)
                {
                    if (!a.IsOptional)
                    {
                        monitor.Error($"{a.ToString()}: Unable to resolve non optional.");
                    }
                }
                else
                {
                    // Ambient property setting: when it is a StObj, it depends on the relationship between the items.
                    MutableItem?resolved = value as MutableItem;
                    // If the property value is a StObj, extracts its actual value.
                    if (resolved != null)
                    {
                        #region AmbientProperty is a StObj.

                        MutableItem?highestSetSource   = null;
                        MutableItem?highestSetResolved = null;

                        MutableItem?        source     = this;
                        AmbientPropertyInfo?sourceProp = a.AmbientPropertyInfo;
                        Debug.Assert(sourceProp.Index < source.RealObjectType.AmbientProperties.Count, "This is the way to test if the property is defined at the source level or not.");

                        // Walks up the chain to locate the most abstract compatible slice.
                        {
                            MutableItem?genResolved = resolved.Generalization;
                            while (genResolved != null && sourceProp.PropertyType.IsAssignableFrom(genResolved.ClassType))
                            {
                                resolved    = genResolved;
                                genResolved = genResolved.Generalization;
                            }
                        }
                        if (resolved._trackedAmbientProperties != null)
                        {
                            if (resolved._trackAmbientPropertiesMode == TrackAmbientPropertiesMode.AddPropertyHolderAsChildren ||
                                resolved._trackAmbientPropertiesMode == TrackAmbientPropertiesMode.PropertyHolderRequiresThis)
                            {
                                highestSetSource   = source;
                                highestSetResolved = resolved;
                            }
                            resolved._trackedAmbientProperties.Add(new TrackedAmbientPropertyInfo(source, sourceProp));
                        }
                        // Walks up the source chain and adjusts the resolved target accordingly.
                        while ((source = source.Generalization) != null && resolved._needsTrackedAmbientProperties)
                        {
                            bool sourcePropChanged = false;
                            Debug.Assert((source == null) == (sourceProp == null));
                            // If source does not define anymore sourceProp. Does it define the property with another type?
                            while (source != null && sourceProp !.Index >= source.RealObjectType.AmbientProperties.Count)
                            {
                                sourcePropChanged = true;
                                if ((sourceProp = sourceProp.Generalization) == null)
                                {
                                    // No property defined anymore at this level: we do not have anything more to do.
                                    source = null;
                                }
                            }
                            if (source == null)
                            {
                                break;
                            }
                            Debug.Assert(sourceProp != null);
                            // Walks up the chain to locate the most abstract compatible slice.
                            if (sourcePropChanged)
                            {
                                MutableItem?genResolved = resolved.Generalization;
                                while (genResolved != null && sourceProp.PropertyType.IsAssignableFrom(genResolved.ClassType))
                                {
                                    resolved    = genResolved;
                                    genResolved = genResolved.Generalization;
                                }
                            }
                            if (resolved._trackedAmbientProperties != null)
                            {
                                if (resolved._trackAmbientPropertiesMode == TrackAmbientPropertiesMode.AddPropertyHolderAsChildren ||
                                    resolved._trackAmbientPropertiesMode == TrackAmbientPropertiesMode.PropertyHolderRequiresThis)
                                {
                                    highestSetSource   = source;
                                    highestSetResolved = resolved;
                                }
                                resolved._trackedAmbientProperties.Add(new TrackedAmbientPropertyInfo(source, sourceProp));
                            }
                        }
                        if (highestSetSource != null)
                        {
                            Debug.Assert(highestSetResolved != null);
                            highestSetSource.AddPreConstructProperty(a.AmbientPropertyInfo.SettablePropertyInfo, highestSetResolved, valueCollector);
                        }
                        else
                        {
                            AddPostBuildProperty(a.AmbientPropertyInfo.SettablePropertyInfo, resolved, valueCollector);
                        }
                        #endregion
                    }
                    else
                    {
                        RootGeneralization.AddPreConstructProperty(a.AmbientPropertyInfo.SettablePropertyInfo, value, valueCollector);
                    }
                }
            }
        }