| File: BackEnd\Components\Communications\TranslatorExtensions.cs | Web Access |
| Project: src\msbuild\src\Build\Microsoft.Build.csproj (Microsoft.Build) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Concurrent; using System.Reflection; using Microsoft.Build.Collections; using Microsoft.Build.Execution; using Microsoft.Build.Framework; #nullable disable namespace Microsoft.Build.BackEnd { /// <summary> /// This class is responsible for serializing and deserializing anything that is not /// officially supported by ITranslator, but that we still want to do /// custom translation of. /// </summary> internal static class TranslatorExtensions { private static readonly Lazy<ConcurrentDictionary<Type, ConstructorInfo>> parameterlessConstructorCache = new Lazy<ConcurrentDictionary<Type, ConstructorInfo>>(() => new ConcurrentDictionary<Type, ConstructorInfo>()); /// <summary> /// Translates a PropertyDictionary of ProjectPropertyInstances. /// </summary> /// <param name="translator">The tranlator doing the translating</param> /// <param name="value">The dictionary to translate.</param> public static void TranslateProjectPropertyInstanceDictionary(this ITranslator translator, ref PropertyDictionary<ProjectPropertyInstance> value) { if (!translator.TranslateNullable(value)) { return; } if (translator.Mode == TranslationDirection.ReadFromStream) { int count = 0; translator.Translate(ref count); value = new PropertyDictionary<ProjectPropertyInstance>(count); for (int i = 0; i < count; i++) { ProjectPropertyInstance instance = null; translator.Translate(ref instance, ProjectPropertyInstance.FactoryForDeserialization); value[instance.Name] = instance; } } else // TranslationDirection.WriteToStream { int count = value.Count; translator.Translate(ref count); foreach (ProjectPropertyInstance instance in value) { ProjectPropertyInstance instanceForSerialization = instance; translator.Translate(ref instanceForSerialization, ProjectPropertyInstance.FactoryForDeserialization); } } } /// <summary> /// Deserialize a type or a subtype by its full name. The type must implement ITranslateable /// </summary> /// <typeparam name="T">Top level type. Serialized types can be of this type, or subtypes</typeparam> /// <returns></returns> public static T FactoryForDeserializingTypeWithName<T>(this ITranslator translator) { string typeName = null; translator.Translate(ref typeName); var type = Type.GetType(typeName); Assumed.NotNull(type, "type cannot be null"); Assumed.True(typeof(T).IsAssignableFrom(type), $"{typeName} must be a {typeof(T).FullName}"); Assumed.True(typeof(ITranslatable).IsAssignableFrom(type), $"{typeName} must be a {nameof(ITranslatable)}"); var parameterlessConstructor = parameterlessConstructorCache.Value.GetOrAdd( type, t => { ConstructorInfo constructor = null; constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, Type.EmptyTypes, null); Assumed.NotNull(constructor, $"{typeName} must have a private parameterless constructor"); return constructor; }); var targetInstanceChild = (ITranslatable)parameterlessConstructor.Invoke(Array.Empty<object>()); targetInstanceChild.Translate(translator); return (T)targetInstanceChild; } public static void TranslateOptionalBuildEventContext(this ITranslator translator, ref BuildEventContext buildEventContext) { if (translator.Mode == TranslationDirection.ReadFromStream) { buildEventContext = translator.Reader.ReadOptionalBuildEventContext(); } else { translator.Writer.WriteOptionalBuildEventContext(buildEventContext); } } } }