public MetadataReference GetMetadataReference(Compilation compilation, ImmutableArray <string> aliases, bool embedInteropTypes) { var key = new MetadataReferenceProperties(MetadataImageKind.Assembly, aliases, embedInteropTypes); using (_gate.DisposableWait()) { if (!_metadataReferences.TryGetValue(key, out var weakMetadata) || !weakMetadata.TryGetTarget(out var metadataReference)) { // here we give out strong reference to compilation. so there is possibility that we end up making 2 compilations for same project alive. // one for final compilation and one for declaration only compilation. but the final compilation will be eventually kicked out from compilation cache // if there is no activity on the project. or the declaration compilation will go away if the project that depends on the reference doesn't have any // activity when it is kicked out from compilation cache. if there is an activity, then both will updated as activity happens. // so simply put, things will go away when compilations are kicked out from the cache or due to user activity. // // there is one case where we could have 2 compilations for same project alive. if a user opens a file that requires a skeleton assembly when the skeleton // assembly project didn't reach the final stage yet and then the user opens another document that is part of the skeleton assembly project // and then never change it. declaration compilation will be alive by skeleton assembly and final compilation will be alive by background compiler. metadataReference = _image.CreateReference(aliases, embedInteropTypes, new DeferredDocumentationProvider(compilation)); weakMetadata = new WeakReference <MetadataReference>(metadataReference); _metadataReferences[key] = weakMetadata; } return(metadataReference); } }