SmartDIContainer.cs
/// <summary>
/// Fetches an object of the requested type.
/// If the object does not exist, creates it.
/// In certain cases, stores the object.
/// </summary>
/// <param name="typeRequestedT">The type to cast the object as.  NOTE that the programmer does this after their Resolve.</param>
/// <param name="ruleRequested">The sort of storage rule to use in managing the resolved object.</param>
/// <param name="boundParent">
/// If the storage rule is <see cref="StorageRules.SharedDependencyBetweenInstances" />,
/// this is the object that will share the resolved object with other peers.
/// </param>
/// <param name="conflictResolver">
/// If supplied, determines which competing resolution will be returned for the type
/// requested.
/// </param>
/// <returns>System.Object.</returns>
Fetches an object of the requested type.
If the object does not exist, creates it.
In certain cases, stores the object.
Fetches an object of the requested type . If the object does not exist creates it . In certain cases stores the object .
public object Resolve
      (
         Type         typeRequestedT,
         StorageRules ruleRequested = StorageRules.AnyAccessLevel,
         object       boundParent   = null,
         Func<ConcurrentDictionary<Type, ITimeStampedCreatorAndStorageRules>, IConflictResolution>
            conflictResolver =
            null
      )
      {
         var qualifyingRegistrations = GetQualifyingRegistrations(typeRequestedT);
         if (qualifyingRegistrations.IsEmpty())
         {
            ThrowArgumentException(nameof(Resolve), "No registered contracts for the type " + typeRequestedT, true);
            return null;
         }
         if (ruleRequested != StorageRules.AnyAccessLevel)
         {
            var storageMatchedQualifyingRegistrations =
               new ConcurrentDictionary<Type, ITimeStampedCreatorAndStorageRules>(
                qualifyingRegistrations.Where(qr =>
                                                 (qr.Value.CreatorsAndStorageRules[typeRequestedT]
                                                    .ProvidedStorageRule == StorageRules.AnyAccessLevel) ||
                                                 (qr.Value.CreatorsAndStorageRules[typeRequestedT]
                                                    .ProvidedStorageRule == ruleRequested)));
            if (storageMatchedQualifyingRegistrations.IsEmpty())
            {
               ThrowArgumentException(nameof(Resolve), "Cannot find a registration for the type ->" +
                                                       typeRequestedT                               +
                                                       "<- using storage rule ->"                   +
                                                       ruleRequested                                + "<-",
                                      true);
               return null;
            }
            qualifyingRegistrations = storageMatchedQualifyingRegistrations;
         }
         if (!qualifyingRegistrations.Any())
         {
            ThrowArgumentException(nameof(Resolve),
                                   "Cannot find a registration for the type ->" + typeRequestedT + "<-");
            return null;
         }
         var resolutionToSeek = default(KeyValuePair<Type, IProvideCreatorAndStorageRule>);
         var qualifyingMasterType = default(Type);
         if (CannotResolveConflicts(conflictResolver, qualifyingRegistrations, ref qualifyingMasterType,
                                    ref resolutionToSeek))
         {
            ThrowOperationException(nameof(Resolve), "Cannot determine which one of " +
                                                     qualifyingRegistrations.Count    +
                                                     " registrations to use through the provided conflict resolver.");
            return null;
         }
         if (resolutionToSeek.IsAnEqualObjectTo(default(KeyValuePair<Type, IProvideCreatorAndStorageRule>)))
         {
            if (CannotFindObviousChoice(typeRequestedT, qualifyingRegistrations, ref resolutionToSeek))
            {
               ThrowArgumentException(nameof(Resolve),
                                      "Unexpected error fetching a known contract for the type " + typeRequestedT);
               return null;
            }
         }
         if (qualifyingMasterType.IsAnEqualObjectTo(default(Type)))
         {
            qualifyingMasterType = qualifyingRegistrations.OrderBy(qr => qr.Value.WhenAdded).First().Key;
         }
         if (resolutionToSeek.IsAnEqualObjectTo(default(KeyValuePair<Type, IProvideCreatorAndStorageRule>)))
         {
            ThrowArgumentException(nameof(Resolve), "Cannot find a registration for the type " + typeRequestedT);
            return null;
         }
         if (!qualifyingMasterType.IsTypeOrAssignableFromType(typeRequestedT))
         {
            ThrowOperationException(nameof(Resolve), "Cannot save an instance of ->" + qualifyingMasterType +
                                                     "<- as ->"                      + typeRequestedT       + "<-");
            return null;
         }
         var finalTypeRequestedT = resolutionToSeek.Key;
         ruleRequested = resolutionToSeek.Value.ProvidedStorageRule;
         if ((ruleRequested == StorageRules.SharedDependencyBetweenInstances) && (boundParent == null))
         {
            ThrowArgumentException(nameof(Resolve),
                                   "Cannot resolve a shared type without a bound instance to attach it to. To share a variable without a bound instance, use a global singleton.");
            return null;
         }
         if (ruleRequested == StorageRules.GlobalSingleton)
         {
            if (_globalSingletonsByType.ContainsKey(finalTypeRequestedT))
            {
               var foundGlobalInstance = _globalSingletonsByType[finalTypeRequestedT];
               if (foundGlobalInstance == null)
               {
                  _globalSingletonsByType.Remove(finalTypeRequestedT);
               }
               else
               {
                  return foundGlobalInstance;
               }
            }
         }
         else if (ruleRequested == StorageRules.SharedDependencyBetweenInstances)
         {
            var foundSharedInstances =
               _sharedInstancesWithBoundMembers.FirstOrDefault(si =>
                                                                  (si.Key != null) && (si.Key.GetType() ==
                                                                           qualifyingMasterType));
            if (foundSharedInstances.IsNotAnEqualObjectTo(default(KeyValuePair<object, List<object>>)))
            {
               var illegalBoundParent = ReferenceEquals(boundParent, foundSharedInstances.Key);
               if (illegalBoundParent)
               {
                  ThrowArgumentException(nameof(Resolve), "A returned instance cannot be bound to itself.");
                  return null;
               }
               var parentIsAlreadyStored = foundSharedInstances.Value.Any(existingBoundParent =>
                                                                             ReferenceEquals(existingBoundParent,
                                                                                boundParent));
               if (!parentIsAlreadyStored)
               {
                  _sharedInstancesWithBoundMembers[foundSharedInstances.Key].Add(boundParent);
               }
               return foundSharedInstances.Key;
            }
         }
         object instantiatedObject = null;
         if (ProvidedCreatorFailed(resolutionToSeek, finalTypeRequestedT, ref instantiatedObject))
         {
            ThrowArgumentException(nameof(Resolve),
                                   "Provided constructor did not create the expected type ->" + finalTypeRequestedT +
                                   "<-");
            return null;
         }
         if (CouldNotCreateObject(qualifyingMasterType, ref instantiatedObject))
         {
            ThrowOperationException(nameof(Resolve),
                                    "Could not construct an object for base type ->" + qualifyingMasterType + "<-");
            return null;
         }
         switch (ruleRequested)
         {
            case StorageRules.GlobalSingleton:
               CreateSingletonInstance(instantiatedObject, finalTypeRequestedT);
               break;
            case StorageRules.SharedDependencyBetweenInstances:
               CreateSharedInstances(instantiatedObject, finalTypeRequestedT, boundParent);
               break;
         }
         return instantiatedObject;
      }
public object Resolve ( Type typeRequestedT , StorageRules ruleRequested = StorageRules . AnyAccessLevel , object boundParent = null , Func < ConcurrentDictionary < Type , ITimeStampedCreatorAndStorageRules > , IConflictResolution > conflictResolver = null ) { var qualifyingRegistrations = GetQualifyingRegistrations ( typeRequestedT ) ; if ( qualifyingRegistrations . IsEmpty ( ) ) { ThrowArgumentException ( nameof ( Resolve ) , " " + typeRequestedT , true ) ; return null ; } if ( ruleRequested != StorageRules . AnyAccessLevel ) { var storageMatchedQualifyingRegistrations = new ConcurrentDictionary < Type , ITimeStampedCreatorAndStorageRules > ( qualifyingRegistrations . Where ( qr => ( qr . Value . CreatorsAndStorageRules [ typeRequestedT ] . ProvidedStorageRule == StorageRules . AnyAccessLevel ) || ( qr . Value . CreatorsAndStorageRules [ typeRequestedT ] . ProvidedStorageRule == ruleRequested ) ) ) ; if ( storageMatchedQualifyingRegistrations . IsEmpty ( ) ) { ThrowArgumentException ( nameof ( Resolve ) , " " + typeRequestedT + " " + ruleRequested + " " , true ) ; return null ; } qualifyingRegistrations = storageMatchedQualifyingRegistrations ; } if ( ! qualifyingRegistrations . Any ( ) ) { ThrowArgumentException ( nameof ( Resolve ) , " " + typeRequestedT + " " ) ; return null ; } var resolutionToSeek = default ( KeyValuePair < Type , IProvideCreatorAndStorageRule > ) ; var qualifyingMasterType = default ( Type ) ; if ( CannotResolveConflicts ( conflictResolver , qualifyingRegistrations , ref qualifyingMasterType , ref resolutionToSeek ) ) { ThrowOperationException ( nameof ( Resolve ) , " " + qualifyingRegistrations . Count + " " ) ; return null ; } if ( resolutionToSeek . IsAnEqualObjectTo ( default ( KeyValuePair < Type , IProvideCreatorAndStorageRule > ) ) ) { if ( CannotFindObviousChoice ( typeRequestedT , qualifyingRegistrations , ref resolutionToSeek ) ) { ThrowArgumentException ( nameof ( Resolve ) , " " + typeRequestedT ) ; return null ; } } if ( qualifyingMasterType . IsAnEqualObjectTo ( default ( Type ) ) ) { qualifyingMasterType = qualifyingRegistrations . OrderBy ( qr => qr . Value . WhenAdded ) . First ( ) . Key ; } if ( resolutionToSeek . IsAnEqualObjectTo ( default ( KeyValuePair < Type , IProvideCreatorAndStorageRule > ) ) ) { ThrowArgumentException ( nameof ( Resolve ) , " " + typeRequestedT ) ; return null ; } if ( ! qualifyingMasterType . IsTypeOrAssignableFromType ( typeRequestedT ) ) { ThrowOperationException ( nameof ( Resolve ) , " " + qualifyingMasterType + " " + typeRequestedT + " " ) ; return null ; } var finalTypeRequestedT = resolutionToSeek . Key ; ruleRequested = resolutionToSeek . Value . ProvidedStorageRule ; if ( ( ruleRequested == StorageRules . SharedDependencyBetweenInstances ) && ( boundParent == null ) ) { ThrowArgumentException ( nameof ( Resolve ) , " " ) ; return null ; } if ( ruleRequested == StorageRules . GlobalSingleton ) { if ( _globalSingletonsByType . ContainsKey ( finalTypeRequestedT ) ) { var foundGlobalInstance = _globalSingletonsByType [ finalTypeRequestedT ] ; if ( foundGlobalInstance == null ) { _globalSingletonsByType . Remove ( finalTypeRequestedT ) ; } else { return foundGlobalInstance ; } } } else if ( ruleRequested == StorageRules . SharedDependencyBetweenInstances ) { var foundSharedInstances = _sharedInstancesWithBoundMembers . FirstOrDefault ( si => ( si . Key != null ) && ( si . Key . GetType ( ) == qualifyingMasterType ) ) ; if ( foundSharedInstances . IsNotAnEqualObjectTo ( default ( KeyValuePair < object , List < object > > ) ) ) { var illegalBoundParent = ReferenceEquals ( boundParent , foundSharedInstances . Key ) ; if ( illegalBoundParent ) { ThrowArgumentException ( nameof ( Resolve ) , " " ) ; return null ; } var parentIsAlreadyStored = foundSharedInstances . Value . Any ( existingBoundParent => ReferenceEquals ( existingBoundParent , boundParent ) ) ; if ( ! parentIsAlreadyStored ) { _sharedInstancesWithBoundMembers [ foundSharedInstances . Key ] . Add ( boundParent ) ; } return foundSharedInstances . Key ; } } object instantiatedObject = null ; if ( ProvidedCreatorFailed ( resolutionToSeek , finalTypeRequestedT , ref instantiatedObject ) ) { ThrowArgumentException ( nameof ( Resolve ) , " " + finalTypeRequestedT + " " ) ; return null ; } if ( CouldNotCreateObject ( qualifyingMasterType , ref instantiatedObject ) ) { ThrowOperationException ( nameof ( Resolve ) , " " + qualifyingMasterType + " " ) ; return null ; } switch ( ruleRequested ) { case StorageRules . GlobalSingleton : CreateSingletonInstance ( instantiatedObject , finalTypeRequestedT ) ; break ; case StorageRules . SharedDependencyBetweenInstances : CreateSharedInstances ( instantiatedObject , finalTypeRequestedT , boundParent ) ; break ; } return instantiatedObject ; }
Fetches an object of the requested type.
Fetches an object of the requested type .
// We have at least one qualifying registration. // Filter against storage rules. // If the qualifying registration is 'any', then any requested storage works. // If the requested storage rule is 'any', that also works. // Otherwise, the qualifying registration storage rule and the requested storage rule *must* match. // The rules qualify if they are "all" or if they match the requested rule. // Return this value to the original collection. // Will need to determine the type we are creating (not the typeRequestedT that the user will cast this as) // If more than one registration, see if we can decide with the conflict resolver // If no resolutionToSeek yet (steps above failed), find it through another means. // Unconditional; applies to any count for qualifyingRegistrations // If unset, set now // Take the *first* qualifying registration made // The same as having no qualifying registrations. Should never occur based on the checks above. // Verify that the result will be legal, since we will cast as TypeRequestedT // Now we have: // 1. A master type to create; // 2. A TypeRequestedT type to save as -- these might not be the same, but must relate class-design-wise // 3. A resolution to seek that might include an instance creator; // 4. If no instance creator, then we will use activator create instance // We switch here; the resolutionToSeek now has authority over our process. // This means that we also accept the resolutionToSeek's Type // Verify that we do not have an incompatible rules request and bound object // If the instance is invalid -- which should not generally occur -- remove it. // ELSE return it // ELSE proceed to creating the instance // There is a remote possibility that after being stored as a shared instance, they key will get garbage //    collected, making it null. This case is ignored because we cannot get its type, etc. // NOTE that we ask for the qualifyingMasterType.  That is what we add down below (see line 842, //    "_sharedInstancesWithBoundMembers.Add(sharedInstance, new List<object>(boundParents));" -- //    the key, sharedInstance, is of type qualifyingMasterType. // If valid (not empty) // Add our bound object to the list... maybe make sure it's not there already.. // Also ensure that we are not trying to bind the foundSharedInstances.Key -- //    that is the instance being returned, so cannot act as its own parent. // This is a critical error, so wil throw rather than return a value. // If the bound parent is already there, do not re-add it. // ReSharper disable once AssignNullToNotNullAttribute // Return the key object, as that is the one that is being shared between the list of bound instances // ELSE must instantiate // Try the creator // The last step is to determine if we have to save the new object in our container. // If global, yes -- this will only occur once
None
typeRequestedT
Type
The type to cast the object as.  NOTE that the programmer does this after their Resolve.
The type to cast the object as . NOTE that the programmer does this after their Resolve .
ruleRequested
StorageRules
The sort of storage rule to use in managing the resolved object.
The sort of storage rule to use in managing the resolved object .
boundParent
object
If the storage rule is ,
this is the object that will share the resolved object with other peers.
If the storage rule is this is the object that will share the resolved object with other peers .
conflictResolver
Func<ConcurrentDictionary<Type, ITimeStampedCreatorAndStorageRules>, IConflictResolution>
If supplied, determines which competing resolution will be returned for the type
requested.
If supplied determines which competing resolution will be returned for the type requested .