public static void TryAdd_ConditionallyAdds()
        {
            var cwt = new ConditionalWeakTable <object, object>();

            object value1 = new object();
            object value2 = new object();
            object found;

            object key1 = new object();

            Assert.True(cwt.TryAdd(key1, value1));
            Assert.False(cwt.TryAdd(key1, value2));
            Assert.True(cwt.TryGetValue(key1, out found));
            Assert.Same(value1, found);
            Assert.Equal(1, cwt.Count());

            object key2 = new object();

            Assert.True(cwt.TryAdd(key2, value1));
            Assert.False(cwt.TryAdd(key2, value2));
            Assert.True(cwt.TryGetValue(key2, out found));
            Assert.Same(value1, found);
            Assert.Equal(2, cwt.Count());

            GC.KeepAlive(key1);
            GC.KeepAlive(key2);
        }
예제 #2
0
        /// <summary>
        /// Returns the portable PDB reader for the assembly path
        /// </summary>
        /// <param name="assembly">Managed Assembly to be used as a cache key</param>
        /// <param name="assemblyPath">
        /// File path of the assembly or null if the module is dynamic (generated by Reflection.Emit).
        /// </param>
        /// <param name="loadedPeAddress">
        /// Loaded PE image address or zero if the module is dynamic (generated by Reflection.Emit).
        /// Dynamic modules have their PDBs (if any) generated to an in-memory stream
        /// (pointed to by <paramref name="inMemoryPdbAddress"/> and <paramref name="inMemoryPdbSize"/>).
        /// </param>
        /// <param name="loadedPeSize">loaded PE image size</param>
        /// <param name="isFileLayout">if true, the PE image is file layout, false it is loaded layout</param>
        /// <param name="inMemoryPdbAddress">in memory PDB address or zero</param>
        /// <param name="inMemoryPdbSize">in memory PDB size</param>
        /// <returns>reader</returns>
        /// <remarks>
        /// Accounts for unloadable and dynamic types by keying the cache on the managed Assembly. The
        /// underlying ConditionalWeakTable doesn't keep the assembly alive, so cached types will be
        /// correctly invalidated when the Assembly is unloaded by the GC.
        /// </remarks>
        private unsafe MetadataReader?TryGetReader(Assembly assembly, string assemblyPath, IntPtr loadedPeAddress, int loadedPeSize, bool isFileLayout, IntPtr inMemoryPdbAddress, int inMemoryPdbSize)
        {
            if ((loadedPeAddress == IntPtr.Zero || assemblyPath == null) && inMemoryPdbAddress == IntPtr.Zero)
            {
                // Dynamic or in-memory module without symbols (they would be in-memory if they were available).
                return(null);
            }

            MetadataReaderProvider?provider;

            while (!_metadataCache.TryGetValue(assembly, out provider))
            {
                provider = inMemoryPdbAddress != IntPtr.Zero ?
                           TryOpenReaderForInMemoryPdb(inMemoryPdbAddress, inMemoryPdbSize) :
                           TryOpenReaderFromAssemblyFile(assemblyPath !, loadedPeAddress, loadedPeSize, isFileLayout);

                if (_metadataCache.TryAdd(assembly, provider))
                {
                    break;
                }

                provider?.Dispose();
            }

            // The reader has already been open, so this doesn't throw.
            return(provider?.GetMetadataReader());
        }
        public static void Add(int numObjects, bool tryAdd)
        {
            // Isolated to ensure we drop all references even in debug builds where lifetime is extended by the JIT to the end of the method
            Func <int, Tuple <ConditionalWeakTable <object, object>, WeakReference[], WeakReference[]> > body = count =>
            {
                object[] keys   = Enumerable.Range(0, count).Select(_ => new object()).ToArray();
                object[] values = Enumerable.Range(0, count).Select(_ => new object()).ToArray();
                var      cwt    = new ConditionalWeakTable <object, object>();

                for (int i = 0; i < count; i++)
                {
                    if (tryAdd)
                    {
                        Assert.True(cwt.TryAdd(keys[i], values[i]));
                    }
                    else
                    {
                        cwt.Add(keys[i], values[i]);
                    }
                }

                for (int i = 0; i < count; i++)
                {
                    object value;
                    Assert.True(cwt.TryGetValue(keys[i], out value));
                    Assert.Same(values[i], value);
                    Assert.Same(value, cwt.GetOrCreateValue(keys[i]));
                    Assert.Same(value, cwt.GetValue(keys[i], _ => new object()));
                }

                return(Tuple.Create(cwt, keys.Select(k => new WeakReference(k)).ToArray(), values.Select(v => new WeakReference(v)).ToArray()));
            };

            Tuple <ConditionalWeakTable <object, object>, WeakReference[], WeakReference[]> result = body(numObjects);

            GC.Collect();

            Assert.NotNull(result.Item1);

            for (int i = 0; i < numObjects; i++)
            {
                Assert.False(result.Item2[i].IsAlive, $"Expected not to find key #{i}");
                Assert.False(result.Item3[i].IsAlive, $"Expected not to find value #{i}");
            }
        }
예제 #4
0
        /// <summary>
        /// Set a callback for resolving native library imports from an assembly.
        /// This per-assembly resolver is the first attempt to resolve native library loads
        /// initiated by this assembly.
        ///
        /// Only one resolver can be registered per assembly.
        /// Trying to register a second resolver fails with InvalidOperationException.
        /// </summary>
        /// <param name="assembly">The assembly for which the resolver is registered</param>
        /// <param name="resolver">The resolver callback to register</param>
        /// <exception cref="System.ArgumentNullException">If assembly or resolver is null</exception>
        /// <exception cref="System.ArgumentException">If a resolver is already set for this assembly</exception>
        public static void SetDllImportResolver(Assembly assembly, DllImportResolver resolver)
        {
            ArgumentNullException.ThrowIfNull(assembly);
            ArgumentNullException.ThrowIfNull(resolver);

            if (assembly is not RuntimeAssembly)
            {
                throw new ArgumentException(SR.Argument_MustBeRuntimeAssembly);
            }

            if (s_nativeDllResolveMap == null)
            {
                Interlocked.CompareExchange(ref s_nativeDllResolveMap,
                                            new ConditionalWeakTable <Assembly, DllImportResolver>(), null);
            }

            if (!s_nativeDllResolveMap.TryAdd(assembly, resolver))
            {
                throw new InvalidOperationException(SR.InvalidOperation_CannotRegisterSecondResolver);
            }
        }