|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.CodeDom;
namespace System.ComponentModel.Design.Serialization;
/// <summary>
/// Code model serializer for enum types.
/// </summary>
internal class EnumCodeDomSerializer : CodeDomSerializer
{
private static EnumCodeDomSerializer? s_defaultSerializer;
/// <summary>
/// Retrieves a default static instance of this serializer.
/// </summary>
internal static new EnumCodeDomSerializer Default => s_defaultSerializer ??= new EnumCodeDomSerializer();
/// <summary>
/// Serializes the given object into a CodeDom object.
/// </summary>
public override object Serialize(IDesignerSerializationManager manager, object? value)
{
CodeExpression? expression = null;
if (value is not Enum enumValue)
{
Debug.Fail("Enum serializer called for non-enum object.");
return null!;
}
bool needCast = false;
Enum[] values;
TypeConverter? converter = TypeDescriptor.GetConverter(enumValue);
if (converter is not null && converter.CanConvertTo(typeof(Enum[])))
{
values = (Enum[])converter.ConvertTo(enumValue, typeof(Enum[]))!;
needCast = (values.Length > 1);
}
else
{
values = [enumValue];
needCast = true;
}
// EnumConverter (and anything that is overridden to support enums)
// should be providing us a conversion to Enum[] for flag styles.
// If it doesn't, we will emit a warning and just do a cast from the enum value.
CodeTypeReferenceExpression enumType = new(enumValue.GetType());
// If names is of length 1, then this is a simple field reference. Otherwise,
// it is an or-d combination of expressions.
// We now need to serialize the enum terms as fields. We new up an EnumConverter to do
// that. We cannot use the type's own converter since it might have a different string
// representation for its values. Hardcoding is okay in this case, since all we want is
// the enum's field name. Simply doing ToString() will not give us any validation.
TypeConverter enumConverter = new EnumConverter(enumValue.GetType());
foreach (Enum term in values)
{
string? termString = enumConverter?.ConvertToString(term);
if (!string.IsNullOrEmpty(termString))
{
CodeExpression newExpression = new CodeFieldReferenceExpression(enumType, termString);
if (expression is null)
{
expression = newExpression;
}
else
{
expression = new CodeBinaryOperatorExpression(expression, CodeBinaryOperatorType.BitwiseOr, newExpression);
}
}
}
// If we had to combine multiple names, wrap the result in an appropriate cast.
if (expression is not null && needCast)
{
expression = new CodeCastExpression(enumValue.GetType(), expression);
}
return expression!;
}
}
|