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); }
/// <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}"); } }
/// <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); } }