| File: Symbols\AnonymousTypes\SynthesizedSymbols\AnonymousType.TemplateSymbol.cs | Web Access |
| Project: src\roslyn\src\Compilers\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.csproj (Microsoft.CodeAnalysis.CSharp) |
// 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. #nullable disable using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using Microsoft.CodeAnalysis.CSharp.Emit; using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Symbols { internal sealed partial class AnonymousTypeManager { /// <summary> /// Represents an anonymous type 'template' which is a generic type to be used for all /// anonymous types having the same structure, i.e. the same number of fields and field names. /// </summary> internal sealed class AnonymousTypeTemplateSymbol : AnonymousTypeOrDelegateTemplateSymbol { private readonly ImmutableArray<TypeParameterSymbol> _typeParameters; private readonly ImmutableArray<Symbol> _members; /// <summary> This list consists of synthesized method symbols for ToString, /// Equals and GetHashCode which are not part of symbol table </summary> internal readonly ImmutableArray<MethodSymbol> SpecialMembers; /// <summary> Properties defined in the template </summary> internal readonly ImmutableArray<AnonymousTypePropertySymbol> Properties; /// <summary> Maps member names to symbol(s) </summary> private readonly MultiDictionary<string, Symbol> _nameToSymbols = new MultiDictionary<string, Symbol>(); internal AnonymousTypeTemplateSymbol(AnonymousTypeManager manager, AnonymousTypeDescriptor typeDescr) : base(manager, typeDescr.Location) { this.TypeDescriptorKey = typeDescr.Key; int fieldsCount = typeDescr.Fields.Length; int membersCount = fieldsCount * 3 + 1; // members var membersBuilder = ArrayBuilder<Symbol>.GetInstance(membersCount); var propertiesBuilder = ArrayBuilder<AnonymousTypePropertySymbol>.GetInstance(fieldsCount); var typeParametersBuilder = ArrayBuilder<TypeParameterSymbol>.GetInstance(fieldsCount); // Process fields for (int fieldIndex = 0; fieldIndex < fieldsCount; fieldIndex++) { AnonymousTypeField field = typeDescr.Fields[fieldIndex]; // Add a type parameter AnonymousTypeParameterSymbol typeParameter = new AnonymousTypeParameterSymbol(this, fieldIndex, GeneratedNames.MakeAnonymousTypeParameterName(field.Name), allowsRefLikeType: false); typeParametersBuilder.Add(typeParameter); // Add a property AnonymousTypePropertySymbol property = new AnonymousTypePropertySymbol(this, field, TypeWithAnnotations.Create(typeParameter), fieldIndex); propertiesBuilder.Add(property); // Property related symbols membersBuilder.Add(property); membersBuilder.Add(property.BackingField); membersBuilder.Add(property.GetMethod); } _typeParameters = typeParametersBuilder.ToImmutableAndFree(); this.Properties = propertiesBuilder.ToImmutableAndFree(); // Add a constructor membersBuilder.Add(new AnonymousTypeConstructorSymbol(this, this.Properties)); _members = membersBuilder.ToImmutableAndFree(); Debug.Assert(membersCount == _members.Length); // fill nameToSymbols map foreach (var symbol in _members) { _nameToSymbols.Add(symbol.Name, symbol); } // special members: Equals, GetHashCode, ToString this.SpecialMembers = ImmutableArray.Create<MethodSymbol>( new AnonymousTypeEqualsMethodSymbol(this), new AnonymousTypeGetHashCodeMethodSymbol(this), new AnonymousTypeToStringMethodSymbol(this)); } internal AnonymousTypeKey GetAnonymousTypeKey() { var properties = Properties.SelectAsArray(p => new AnonymousTypeKeyField(p.Name, isKey: false, ignoreCase: false)); return new AnonymousTypeKey(properties); } internal override string TypeDescriptorKey { get; } public override TypeKind TypeKind { get { return TypeKind.Class; } } internal override bool HasDeclaredRequiredMembers => false; internal override bool IsClosed => false; internal override ImmutableArray<NamedTypeSymbol> CandidateClosedSubtypeDefinitions => []; public override ImmutableArray<Symbol> GetMembers() { return _members; } internal override IEnumerable<FieldSymbol> GetFieldsToEmit() { foreach (var m in this.GetMembers()) { switch (m.Kind) { case SymbolKind.Field: yield return (FieldSymbol)m; break; } } } public override ImmutableArray<Symbol> GetMembers(string name) { var symbols = _nameToSymbols[name]; var builder = ArrayBuilder<Symbol>.GetInstance(symbols.Count); foreach (var symbol in symbols) { builder.Add(symbol); } return builder.ToImmutableAndFree(); } internal override ImmutableArray<NamedTypeSymbol> InterfacesNoUseSiteDiagnostics(ConsList<TypeSymbol> basesBeingResolved) { return ImmutableArray<NamedTypeSymbol>.Empty; } internal override ImmutableArray<NamedTypeSymbol> GetInterfacesToEmit() { return ImmutableArray<NamedTypeSymbol>.Empty; } internal override NamedTypeSymbol BaseTypeNoUseSiteDiagnostics => this.Manager.System_Object; public override ImmutableArray<TypeParameterSymbol> TypeParameters { get { return _typeParameters; } } public override IEnumerable<string> MemberNames { get { return _nameToSymbols.Keys; } } internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder<CSharpAttributeData> attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); AddSynthesizedAttribute(ref attributes, Manager.Compilation.TrySynthesizeAttribute( WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor)); if (Manager.Compilation.Options.OptimizationLevel == OptimizationLevel.Debug) { AddSynthesizedAttribute(ref attributes, TrySynthesizeDebuggerDisplayAttribute()); } } /// <summary> /// Returns a synthesized debugger display attribute or null if one /// could not be synthesized. /// </summary> private SynthesizedAttributeData TrySynthesizeDebuggerDisplayAttribute() { // Escape open '{' with '\' to avoid parsing it as an embedded expression. string displayString; if (this.Properties.Length == 0) { displayString = "\\{ }"; } else { var builder = PooledStringBuilder.GetInstance(); var sb = builder.Builder; sb.Append("\\{ "); int displayCount = Math.Min(this.Properties.Length, 10); for (var fieldIndex = 0; fieldIndex < displayCount; fieldIndex++) { string fieldName = this.Properties[fieldIndex].Name; if (fieldIndex > 0) { sb.Append(", "); } sb.Append(fieldName); sb.Append(" = {"); sb.Append(fieldName); sb.Append('}'); } if (this.Properties.Length > displayCount) { sb.Append(" ..."); } sb.Append(" }"); displayString = builder.ToStringAndFree(); } return Manager.Compilation.TrySynthesizeAttribute( WellKnownMember.System_Diagnostics_DebuggerDisplayAttribute__ctor, arguments: ImmutableArray.Create(new TypedConstant(Manager.System_String, TypedConstantKind.Primitive, displayString)), namedArguments: ImmutableArray.Create(new KeyValuePair<WellKnownMember, TypedConstant>( WellKnownMember.System_Diagnostics_DebuggerDisplayAttribute__Type, new TypedConstant(Manager.System_String, TypedConstantKind.Primitive, "<Anonymous Type>")))); } } } }