WCF Enum By Value Суррогаты для поддержки динамических c перечислений - PullRequest
5 голосов
/ 07 января 2020

Я пытаюсь сделать поддержку WCF безымянным перечислением. Я создал суррогат, который отлично работает, когда его перечисление. Однако, когда это nullable перечисление, оно терпит неудачу при десериализации. Это мой суррогат, который был изменен из этой статьи , мой код отличается, так как я не хочу предоставлять известные типы:

public class EnumValueDataContractSurrogate : IDataContractSurrogate
{
    #region Interface Implementation

    public Type GetDataContractType(Type type)
    {
        return type;
    }

    public object GetObjectToSerialize(object obj, Type targetType)
    {
        if (null == obj)
        {
            return obj;
        }

        if (targetType.IsEnum)
        {
            return EnumExtensions.ChangeToUnderlyingType(targetType, obj);
        }

        if (targetType.IsNullable() && targetType.GetUnderlyingType().IsEnum)
        {
            return (int?)obj;
        }

        return obj;
    }

    // This Method is never invoked for targetType enum/enum?
    // However all the other parameters work fine
    public object GetDeserializedObject(object obj, Type targetType)
    {

        if (targetType.IsNullable())
        {
            targetType = targetType.GetUnderlyingType();
        }

        if ((false == targetType.IsEnum) || (null == obj))
        {
            return obj;
        }

        var stringObj = obj as string;
        if (null != stringObj)
        {
            return Enum.Parse(targetType, stringObj);
        }
        return Enum.ToObject(targetType, obj);
    }

    public void GetKnownCustomDataTypes(Collection<Type> customDataTypes)
    {
        //not used
        return;
    }

    public object GetCustomDataToExport(Type clrType, Type dataContractType)
    {
        //Not used
        return null;
    }

    public object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType)
    {
        //not used
        return null;
    }

    public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
    {
        //not used
        return null;
    }

    public CodeTypeDeclaration ProcessImportedType(CodeTypeDeclaration typeDeclaration, CodeCompileUnit compileUnit)
    {
        //not used
        return typeDeclaration;
    }

    #endregion
}

public static object ChangeToUnderlyingType(Type enumType, object value)
{
    return Convert.ChangeType(value, Enum.GetUnderlyingType(enumType));
}

Когда Enum не обнуляется, все десериализовано нормально.
Когда Enum обнуляется, со значением, WCF не будет десериализовать int в Enum.

EDIT:

Я думаю, это может быть связано с тем, как WCF занимается десериализацией суррогатов. Вот несколько вариантов поведения, которые я заметил и которые могут быть полезны.

  1. При вызове GetDeserializedObject object obj будет заполнен объектом, который уже был десериализован. например, похоже, что десериализация WCF начинается раньше, чем суррогат делает

  2. Когда при вызове с базовым типом GetDeserializedObject фактически никогда не срабатывает, я думаю, это потому, что только суррогатная десериализация работает с объектами

  3. WCF не может сериализовать перечисления в значение, но отлично обрабатывает десериализацию из значения.

Ресурсы:

Это MSDN для суррогатов обработки данных

Как я могу получить обнуляемые (и не обнуляемые) перечисления для сериализации и десериализации строго из значений?

Ответы [ 2 ]

2 голосов
/ 09 января 2020

Нижняя строка не позволяет обрабатывать Nullable<Enum> типы:

  if ((false == targetType.IsEnum) || (null == obj))
  {
      return obj;
  }

Вам также необходимо явно указать тип Nullable<>. Как показано ниже:

if (targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
    targetType = targetType.GetGenericArguments()[0];   
}

Скрипка , которая демонстрирует это.

0 голосов
/ 16 января 2020

Я выложу это как обновление. У меня есть эта работа дальше, чем раньше, теперь корректно сериализуется следующее:

  1. именованные значения для ненулевых перечислений
  2. неназванные значения для ненулевых перечислений
  3. именованные значения для значений nullable

Примечание: я исключил тривиальные методы из суррогата, поскольку они остались прежними:

public class EnumValueDataContractSurrogate : IDataContractSurrogate
{
    public object GetObjectToSerialize(object obj, Type targetType)
    {
        if (targetType.IsEnum && !Enum.IsDefined(targetType, obj))
        {
            return EnumExtensions.ChangeToUnderlyingType(targetType, obj);
        }
        return obj;
    }

    public object GetDeserializedObject(object obj, Type targetType)
    {
        return obj;
    }
}

ПРИМЕЧАНИЕ: It важно упомянуть две вещи, которые я наблюдал.

  1. GetObjectToSerialize targetType никогда не равен нулю, WCF обрабатывает для нас удаление нуля.
  2. Несмотря на то, что WCF не может обрабатывать сериализации перечислений как значений, WCF не имеет проблем с преобразованием обратно в перечисление, не обнуляемое перечисление, следовательно, почему сейчас нет кода в GetDeserializedObject

Отказ от ответственности: это основано на наблюдении программирования, я не мог найти ничего, чтобы полностью поддержать мою претензию в документации WCF. (Но если бы у WCF была хорошая документация, меня бы здесь не было)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...