using System.Collections.Generic;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
var compilation = CSharpCompilation.Create("bla")
.AddReferences(MetadataReference.CreateFromFile(typeof(string ).Assembly.Location))
.AddReferences(MetadataReference.CreateFromFile(typeof(Dictionary<,>).Assembly.Location))
.AddSyntaxTrees(CSharpSyntaxTree.ParseText("class D<TKey>{public static System.Collections.Generic.Dictionary<TKey, string>.ValueCollection d;}"));
new GenericContext(new(){ ["TKey"]=compilation.GetTypeByMetadataName(typeof(int).FullName) })
.SubstituteGenericArgs(compilation.GetTypeByMetadataName("D`1").GetMembers().OfType<IFieldSymbol>().Single().Type)
public record GenericContext (Dictionary<string, ITypeSymbol> typeParameterValues)
public ITypeSymbol SubstituteGenericArgs (ITypeSymbol type) => type switch
INamedTypeSymbol nts when nts.ContainingType is {} ct && ct.IsGenericType => SimpleSubstituteGenericArgs(
SubstituteGenericArgs(ct).GetMembers().OfType<INamedTypeSymbol>().Single(
gv => gv.OriginalDefinition == nts.OriginalDefinition
_ => SimpleSubstituteGenericArgs(type)
public ITypeSymbol SimpleSubstituteGenericArgs(ITypeSymbol type) => type switch
ITypeParameterSymbol tps => typeParameterValues[tps.Name],
INamedTypeSymbol nts when nts.TypeArguments.Length == 0 => nts,
INamedTypeSymbol nts when nts.TypeArguments.Length > 0 => nts.ConstructedFrom.Construct(
nts.TypeArguments.Select(SubstituteGenericArgs).ToArray()