| File: DiagnosticAnalyzer\AnalysisValueProvider.cs | Web Access |
| Project: src\roslyn\src\Compilers\Core\Portable\Microsoft.CodeAnalysis.csproj (Microsoft.CodeAnalysis) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; namespace Microsoft.CodeAnalysis.Diagnostics { internal class AnalysisValueProvider<TKey, TValue> where TKey : class { private readonly Func<TKey, TValue> _computeValue; // This provider holds a weak reference to the key-value pairs, as AnalysisValueProvider might outlive individual compilations. // CompilationAnalysisValueProvider, which wraps this provider and lives for the lifetime of specific compilation, holds a strong reference to the key-value pairs, providing an overall performance benefit. private readonly ConditionalWeakTable<TKey, WrappedValue> _valueCache; private readonly ConditionalWeakTable<TKey, WrappedValue>.CreateValueCallback _valueCacheCallback; internal IEqualityComparer<TKey> KeyComparer { get; private set; } public AnalysisValueProvider(Func<TKey, TValue> computeValue, IEqualityComparer<TKey> keyComparer) { _computeValue = computeValue; KeyComparer = keyComparer ?? EqualityComparer<TKey>.Default; _valueCache = new ConditionalWeakTable<TKey, WrappedValue>(); _valueCacheCallback = new ConditionalWeakTable<TKey, WrappedValue>.CreateValueCallback(ComputeValue); } private sealed class WrappedValue { public WrappedValue(TValue value) { Value = value; } public TValue Value { get; } } private WrappedValue ComputeValue(TKey key) { var value = _computeValue(key); return new WrappedValue(value); } internal bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) { // Catch any exceptions from the computeValue callback, which calls into user code. try { value = _valueCache.GetValue(key, _valueCacheCallback).Value; Debug.Assert(value is object); return true; } catch (Exception) { value = default; return false; } } } }