diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MetadataReferences/VisualStudioMetadataReference.Snapshot.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MetadataReferences/VisualStudioMetadataReference.Snapshot.cs index ef977368d234e3aa6c75eb8b884734fb3e76dd8c..5338963261d1921c5e5dd2f5dc9b84eb895046c6 100644 --- a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MetadataReferences/VisualStudioMetadataReference.Snapshot.cs +++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MetadataReferences/VisualStudioMetadataReference.Snapshot.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Execution; using Microsoft.CodeAnalysis.Host; @@ -31,7 +32,7 @@ internal partial class VisualStudioMetadataReference internal sealed class Snapshot : PortableExecutableReference, ISupportTemporaryStorage { private readonly VisualStudioMetadataReferenceManager _provider; - private readonly DateTime _timestamp; + private readonly Lazy _timestamp; private Exception _error; internal Snapshot(VisualStudioMetadataReferenceManager provider, MetadataReferenceProperties properties, string fullPath) @@ -40,20 +41,29 @@ internal Snapshot(VisualStudioMetadataReferenceManager provider, MetadataReferen Contract.Requires(Properties.Kind == MetadataImageKind.Assembly); _provider = provider; - try - { - _timestamp = FileUtilities.GetFileTimeStamp(this.FilePath); - } - catch (IOException e) - { - // Reading timestamp of a file might fail. - // Let's remember the failure and report it to the compiler when it asks for metadata. - _error = e; - } + _timestamp = new Lazy(() => { + try + { + return FileUtilities.GetFileTimeStamp(this.FilePath); + } + catch (IOException e) + { + // Reading timestamp of a file might fail. + // Let's remember the failure and report it to the compiler when it asks for metadata. + // We could let the Lazy hold onto this (since it knows how to rethrow exceptions), but + // our support of GetStorages needs to gracefully handle the case where we have no timestamp. + // If Lazy had a "IsValueFaulted" we could be cleaner here. + _error = e; + return DateTime.MinValue; + } + }, LazyThreadSafetyMode.PublicationOnly); } protected override Metadata GetMetadataImpl() { + // Fetch the timestamp first, so as to populate _error if needed + var timestamp = _timestamp.Value; + if (_error != null) { throw _error; @@ -61,7 +71,7 @@ protected override Metadata GetMetadataImpl() try { - return _provider.GetMetadata(this.FilePath, _timestamp); + return _provider.GetMetadata(this.FilePath, timestamp); } catch (Exception e) when (SaveMetadataReadingException(e)) { @@ -98,7 +108,7 @@ private string GetDebuggerDisplay() public IEnumerable GetStorages() { - return _provider.GetStorages(this.FilePath, _timestamp); + return _provider.GetStorages(this.FilePath, _timestamp.Value); } } }