private static void ValidateDefaultValueCommon(object defaultValue, Type propertyType, string propertyName, ValidateValueCallback validateValueCallback, bool checkThreadAffinity) { if (!IsValidType(defaultValue, propertyType)) { throw new ArgumentException(SR.Get("DefaultValuePropertyTypeMismatch", propertyName)); } if (defaultValue is Expression) { throw new ArgumentException(SR.Get("DefaultValueMayNotBeExpression")); } if (checkThreadAffinity) { DispatcherObject dispatcherObject = defaultValue as DispatcherObject; if (dispatcherObject != null && dispatcherObject.Dispatcher != null) { ISealable sealable = dispatcherObject as ISealable; if (sealable == null || !sealable.CanSeal) { throw new ArgumentException(SR.Get("DefaultValueMustBeFreeThreaded", propertyName)); } Invariant.Assert(!sealable.IsSealed, "A Sealed ISealable must not have dispatcher affinity"); sealable.Seal(); Invariant.Assert(dispatcherObject.Dispatcher == null, "ISealable.Seal() failed after ISealable.CanSeal returned true"); } } if (validateValueCallback != null && !validateValueCallback(defaultValue)) { throw new ArgumentException(SR.Get("DefaultValueInvalid", propertyName)); } }
/// <summary> /// Recursively seal an object /// </summary> /// <param name="o">object to be recursively sealed</param> public void SealRecursively(object o) { // stop when we detect re-entry (reference loop) if (o == null || processStack.Contains(o)) { return; } // stops if o is not ISealable and we are not in deeper mode if (!(deeper || o is ISealable)) { return; } //if (isDebug) s_log.Debug("DeepSeal object: [" + o + "]"); // keep track of objects being processed, so we can detect re-entry processStack.Push(o); try { // we need to do generic collection first for two reasons: // 1. this is by contract in none deeper mode. see the // documentation of DealSeal methods for detail. // 2. if a dictionary implements both generic and non-generic, // foreach returns KeyValuePair instead of DictionaryEntry. bool isProcessed = TryProcessGenericCollection(o); // try to process as none generic collection if (!isProcessed) { isProcessed = TryProcessCollection(o); } // if o is not a collection, seal its all properties. if (!isProcessed) { DeepSealProperties(o); } // seal the object itself ISealable s = o as ISealable; if (s != null && !s.IsSealed) { s.Seal(); } } finally { processStack.Pop(); } }
private static void ValidateDefaultValueCommon( object defaultValue, Type propertyType, string propertyName, ValidateValueCallback validateValueCallback, bool checkThreadAffinity) { // Ensure default value is the correct type if (!IsValidType(defaultValue, propertyType)) { throw new ArgumentException(SR.Format(SR.DefaultValuePropertyTypeMismatch, propertyName)); } // An Expression used as default value won't behave as expected since // it doesn't get evaluated. We explicitly fail it here. if (defaultValue is Expression) { throw new ArgumentException(SR.DefaultValueMayNotBeExpression); } if (checkThreadAffinity) { // If the default value is a DispatcherObject with thread affinity // we cannot accept it as a default value. If it implements ISealable // we attempt to seal it; if not we throw an exception. Types not // deriving from DispatcherObject are allowed - it is up to the user to // make any custom types free-threaded. DispatcherObject dispatcherObject = defaultValue as DispatcherObject; if (dispatcherObject != null && dispatcherObject.Dispatcher != null) { // Try to make the DispatcherObject free-threaded if it's an // ISealable. ISealable valueAsISealable = dispatcherObject as ISealable; if (valueAsISealable != null && valueAsISealable.CanSeal) { Invariant.Assert(!valueAsISealable.IsSealed, "A Sealed ISealable must not have dispatcher affinity"); valueAsISealable.Seal(); Invariant.Assert(dispatcherObject.Dispatcher == null, "ISealable.Seal() failed after ISealable.CanSeal returned true"); } else { throw new ArgumentException(SR.Format(SR.DefaultValueMustBeFreeThreaded, propertyName)); } } } // After checking for correct type, check default value against // validator (when one is given) if (validateValueCallback != null && !validateValueCallback(defaultValue)) { throw new ArgumentException(SR.Format(SR.DefaultValueInvalid, propertyName)); } }