Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ namespace System.Windows.Markup
namespace System.Windows.Markup
#endif
{
#if !PBTCOMPILER && !TARGETTING35SP1 && !WINDOWS_BASE
#if !PBTCOMPILER && !WINDOWS_BASE
/// <summary>
/// This attribute is placed on a class to identify the property that will
/// function as an Name for the given class
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,9 @@ public static bool TryGetProperty<T>(object instance, AttachableMemberIdentifier
}

// DefaultAttachedPropertyStore is used by the global AttachedPropertyServices to implement
// global attached properties for types which don't implement IAttachedProperties or DO/Dependency Property
// integration for their attached properties.
//
#if !TARGETTING35SP1
// global attached properties for types which don't implement IAttachedProperties or DO/Dependency Property
// integration for their attached properties.

sealed class DefaultAttachedPropertyStore
{
Lazy<ConditionalWeakTable<object, Dictionary<AttachableMemberIdentifier, object>>> instanceStorage =
Expand Down Expand Up @@ -237,314 +236,5 @@ public bool TryGetProperty<T>(object instance, AttachableMemberIdentifier name,
return false;
}
}
#else
//***********************************************WARNING************************************************************
// In CLR4.0 there is ConditionalWeakTable. This implementation is for 3.5 and uses a WeakKey dictionary.
// This implementation does not handle the problem where a key is rooted in a value (or graph of a value).
// This will "leak" (never get cleaned up). If we ship a 3.5 version of System.Xaml.dll we should
// consider adding logic that detects such cycles on Add and throws.
//******************************************************************************************************************
sealed class DefaultAttachedPropertyStore
{
Lazy<WeakDictionary<object, Dictionary<AttachableMemberIdentifier, object>>> instanceStorage =
new Lazy<WeakDictionary<object, Dictionary<AttachableMemberIdentifier, object>>>(
() => new WeakDictionary<object, Dictionary<AttachableMemberIdentifier, object>>(), LazyInitMode.AllowMultipleThreadSafeExecution);

public void CopyPropertiesTo(object instance, KeyValuePair<AttachableMemberIdentifier, object>[] array, int index)
{
if (instanceStorage.IsInitialized)
{
lock (instanceStorage.Value.SyncObject)
{
Dictionary<AttachableMemberIdentifier, object> instanceProperties;
if (instanceStorage.Value.TryGetValue(instance, out instanceProperties))
{
((ICollection<KeyValuePair<AttachableMemberIdentifier, object>>)instanceProperties).CopyTo(array, index);
}
}
}
}

public int GetPropertyCount(object instance)
{
if (instanceStorage.IsInitialized)
{
lock(instanceStorage.Value.SyncObject)
{
Dictionary<AttachableMemberIdentifier, object> instanceProperties;
if (instanceStorage.Value.TryGetValue(instance, out instanceProperties))
{
return instanceProperties.Count;
}
}
}
return 0;
}

// <summary>
// Remove the property 'name'. If the property doesn't exist it returns false.
// </summary>
public bool RemoveProperty(object instance, AttachableMemberIdentifier name)
{
if (instanceStorage.IsInitialized)
{
lock (instanceStorage.Value.SyncObject)
{
Dictionary<AttachableMemberIdentifier, object> instanceProperties;
if (instanceStorage.Value.TryGetValue(instance, out instanceProperties))
{
return instanceProperties.Remove(name);
}
}
}
return false;
}

// <summary>
// Set the property 'name' value to 'value', if the property doesn't currently exist this will add the property
// </summary>
public void SetProperty(object instance, AttachableMemberIdentifier name, object value)
{
//
// Accessing Value forces initialization
lock (instanceStorage.Value.SyncObject)
{
Dictionary<AttachableMemberIdentifier, object> instanceProperties;
if (!instanceStorage.Value.TryGetValue(instance, out instanceProperties))
{
instanceProperties = new Dictionary<AttachableMemberIdentifier, object>();
instanceStorage.Value.Add(instance, instanceProperties);
}
instanceProperties[name] = value;
}
}

// <summary>
// Retrieve the value of the attached property 'name'. If there is not attached property then return false.
// </summary>
public bool TryGetProperty<T>(object instance, AttachableMemberIdentifier name, out T value)
{
if (instanceStorage.IsInitialized)
{
lock (instanceStorage.Value.SyncObject)
{
Dictionary<AttachableMemberIdentifier, object> attachedProperties;
if (instanceStorage.Value.TryGetValue(instance, out attachedProperties))
{
object valueAsObj;
if (attachedProperties.TryGetValue(name, out valueAsObj) &&
valueAsObj is T)
{
value = (T)valueAsObj;
return true;
}
}
}
}
value = default(T);
return false;
}

public class WeakDictionary<K, V>
where K : class
where V : class
{
// Optimally this would be a _real_ dictionary implementation that when it ran across WeakKey's that had
// gone out of scope would immediately at least clear their value and from time to time schedule a real
// cleanup.
Dictionary<WeakKey, V> storage;
object cleanupSyncObject;

public WeakDictionary()
{
if (typeof(K) == typeof(WeakReference))
{
throw new InvalidOperationException();
}

this.cleanupSyncObject = new object();
storage = new Dictionary<WeakDictionary<K, V>.WeakKey, V>();
// kick off the cleanup process...
WeakDictionaryCleanupToken.CreateCleanupToken(this);
}

public int Count
{
get { return storage.Count; }
}

public void Add(K key, V value)
{
storage.Add(new WeakKey(key, false), value);
}

internal object SyncObject
{
get { return this.cleanupSyncObject; }
}

public void Cleanup()
{
List<WeakKey> toClean = null;

// First determine what items have died and can be removed...
lock(cleanupSyncObject)
{
foreach (var key in storage.Keys)
{
bool isAlive, needsCleanup;
key.GetValue(out isAlive, out needsCleanup);
if (!isAlive)
{
if (toClean == null)
{
toClean = new List<WeakKey>();
}
toClean.Add(key);
}
}
}

if (toClean != null)
{
// Second go and remove them...
lock(cleanupSyncObject)
{
// If toClean is > some % of the total size it is probably better
// just to create a new dictionary and migrate some set of items over
// wholesale? It is unclear whether or not this is true.
foreach (var key in toClean)
{
storage.Remove(key);
}
}
}

WeakDictionaryCleanupToken.CreateCleanupToken(this);
}

public bool Remove(K key)
{
return storage.Remove(new WeakKey(key, true));
}

public bool TryGetValue(K key, out V value)
{
return storage.TryGetValue(new WeakKey(key, true), out value);
}

public struct WeakKey : IEquatable<WeakKey>
{
int hashCode;
object reference;

public WeakKey(K key, bool lookup)
{
hashCode = key.GetHashCode();
reference = lookup ? key : (object)new WeakReference(key);
}

public override int GetHashCode()
{
return hashCode;
}

public K GetValue(out bool isAlive, out bool needsCleanup)
{
if (reference == null)
{
isAlive = false;
needsCleanup = false;
return (K)reference;
}

K value;
WeakReference wr = reference as WeakReference;
if (wr != null)
{
value = (K)wr.Target;
isAlive = value != null;
needsCleanup = !isAlive;
if (needsCleanup)
{
// This cleans up the WeakReference now that we know the
// target object is dead...
reference = null;
}
return value;
}

value = reference as K;
if (value != null)
{
isAlive = true;
needsCleanup = false;
return value;
}

throw new InvalidOperationException();
}

public bool Equals(WeakKey other)
{
WeakKey x = this;
WeakKey y = other;
bool xIsAlive, yIsAlive;
bool xNeedsCleanup, yNeedsCleanup;
K xKey = x.GetValue(out xIsAlive, out xNeedsCleanup);
K yKey = y.GetValue(out yIsAlive, out yNeedsCleanup);

// If they are both not alive then they are equivalent
if (!xIsAlive && !yIsAlive)
{
return true;
}

if (!xIsAlive || !yIsAlive)
{
return false;
}

return xKey == yKey;
}
}

// This cleanup token will be immediately thrown away and as a result it will
// (a couple of GCs later) make it into the finalization queue and when finalized
// will kick off a thread-pool job to cleanup the dictionary.

public class WeakDictionaryCleanupToken
{
WeakDictionary<K, V> storage;

WeakDictionaryCleanupToken(WeakDictionary<K, V> storage)
{
this.storage = storage;
}

~WeakDictionaryCleanupToken()
{
// Schedule cleanup
ThreadPool.QueueUserWorkItem((WaitCallback)delegate
{
storage.Cleanup();
});
}

[SuppressMessage("Microsoft.Usage", "CA1806",
Justification = "The point of this method is to create one of these and let it float away... To be finalized...")]
[SuppressMessage("Microsoft.Performance", "CA1804",
Justification = "The point of this method is to create one of these and let it float away... To be finalized...")]
public static void CreateCleanupToken(WeakDictionary<K, V> storage)
{
// Create one of these, the work is done when it is finalized which
// will be at some indeterminate point in the future...
WeakDictionaryCleanupToken token = new WeakDictionaryCleanupToken(storage);
}
}

}
}
#endif
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,7 @@ public ObjectWriterContext(XamlSavedContext savedContext,
XAML3.INameScopeDictionary rootNameScopeDictionary = null;
if (rootNameScope == null)
{
#if TARGETTING35SP1
rootNameScopeDictionary = new NameScopeDictionary(new NameScope());
#else
rootNameScopeDictionary = new NameScope();
#endif
}
else
{
Expand Down Expand Up @@ -90,11 +86,7 @@ public ObjectWriterContext(XamlSchemaContext schemaContext,
XAML3.INameScopeDictionary rootNameScopeDictionary = null;
if (rootNameScope == null)
{
#if TARGETTING35SP1
rootNameScopeDictionary = new NameScopeDictionary(new NameScope());
#else
rootNameScopeDictionary = new NameScope();
#endif
}
else
{
Expand Down Expand Up @@ -814,11 +806,7 @@ private XAML3.INameScopeDictionary LookupNameScopeDictionary(ObjectWriterFrame f
if (frame.Depth == SavedDepth + 1 &&
_settings != null && !_settings.RegisterNamesOnExternalNamescope)
{
#if TARGETTING35SP1
frame.NameScopeDictionary = new NameScopeDictionary(new NameScope());
#else
frame.NameScopeDictionary = new NameScope();
#endif
}
else
{
Expand Down Expand Up @@ -912,11 +900,7 @@ private XAML3.INameScopeDictionary HuntAroundForARootNameScope(ObjectWriterFrame
XAML3.INameScope nameScope = (XAML3.INameScope)_runtime.GetValue(inst, nameScopeProperty, false);
if (nameScope == null)
{
#if TARGETTING35SP1
nameScopeDictionary = new NameScopeDictionary(new NameScope());
#else
nameScopeDictionary = new NameScope();
#endif
_runtime.SetValue(inst, nameScopeProperty, nameScopeDictionary);
}
else
Expand All @@ -942,11 +926,7 @@ private XAML3.INameScopeDictionary HuntAroundForARootNameScope(ObjectWriterFrame
// for our own usage. For IXamlNameResolver() to use.
if (nameScopeDictionary == null)
{
#if TARGETTING35SP1
nameScopeDictionary = new NameScopeDictionary(new NameScope());
#else
nameScopeDictionary = new NameScope();
#endif
}

rootFrame.NameScopeDictionary = nameScopeDictionary;
Expand Down
Loading