コード例 #1
0
        // retrieve the value, using the cache if necessary
        internal object GetValue(object item, PropertyDescriptor pd, bool indexerIsNext)
        {
            if (!ShouldCache(item, pd))
            {
                // normal case - just get the value the old-fashioned way
                return(pd.GetValue(item));
            }
            else
            {
                // lazy creation of the cache
                if (_table == null)
                {
                    _table = new HybridDictionary();
                }

                // look up the value in the cache
                bool          isXLinqCollectionProperty = SystemXmlLinqHelper.IsXLinqCollectionProperty(pd);
                ValueTableKey key   = new ValueTableKey(item, pd);
                object        value = _table[key];

                Action FetchAndCacheValue = () =>
                {
                    // if there's no entry, fetch the value and cache it
                    if (value == null)
                    {
                        if (SystemDataHelper.IsDataSetCollectionProperty(pd))
                        {
                            // intercept GetValue calls for certain ADO properties
                            value = SystemDataHelper.GetValue(item, pd, !FrameworkAppContextSwitches.DoNotUseFollowParentWhenBindingToADODataRelation);
                        }
                        else if (isXLinqCollectionProperty)
                        {
                            // interpose our own value for special XLinq properties
                            value = new XDeferredAxisSource(item, pd);
                        }
                        else
                        {
                            value = pd.GetValue(item);
                        }

                        if (value == null)
                        {
                            value = CachedNull;     // distinguish a null value from no entry
                        }

                        // for DataSet properties, store a weak reference to avoid
                        // a memory leak
                        if (SystemDataHelper.IsDataSetCollectionProperty(pd))
                        {
                            value = new WeakReference(value);
                        }

                        _table[key] = value;
                    }

                    if (SystemDataHelper.IsDataSetCollectionProperty(pd))
                    {
                        // we stored a weak reference - decode it now
                        WeakReference wr = value as WeakReference;
                        if (wr != null)
                        {
                            value = wr.Target;
                        }
                    }
                };

                FetchAndCacheValue();

                if (value == null)
                {
                    // we can only get here if we cached a weak reference
                    // whose target has since been GC'd.  Repeating the call
                    // will refetch the value from the item, and is guaranteed
                    // to set value to non-null.
                    FetchAndCacheValue();
                }

                // decode null, if necessary
                if (value == CachedNull)
                {
                    value = null;
                }
                else if (isXLinqCollectionProperty && !indexerIsNext)
                {
                    // The XLinq properties need special help.  When the path
                    // contains "Elements[Foo]", we should return the interposed
                    // XDeferredAxisSource;  the path worker will then call the XDAS's
                    // indexer with argument "Foo", and obtain the desired
                    // ObservableCollection.  But when the path contains "Elements"
                    // with no indexer, we should return an ObservableCollection
                    // corresponding to the full set of children.
                    // [All this applies to "Descendants" as well.]
                    XDeferredAxisSource xdas = (XDeferredAxisSource)value;
                    value = xdas.FullCollection;
                }

                return(value);
            }
        }