Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deserialize Enums #15

Open
danielwertheim opened this issue Apr 4, 2012 · 21 comments · May be fixed by #64
Open

Deserialize Enums #15

danielwertheim opened this issue Apr 4, 2012 · 21 comments · May be fixed by #64
Labels

Comments

@danielwertheim
Copy link

Tried Serializing with Enums and it worked. Deserializing does not work with Enum. The only option I made available was use Emits.

The model being used is located here: https://github.com/danielwertheim/CompareJsonSerializers/tree/master/Source/CompareJsonSerializers/Model/Customer.cs

//Daniel

@JanWosnitza
Copy link

There are 2 problems:

  • Enums are serialized as doubles (in PocoJsonSerializerStrategy.SerializeEnum( Enum p ))
  • Enums are deserialized as int64 which is not implicit castable to any enum (in PocoJsonSerializerStrategy.DeserializeObject( object value, Type type ))

I changed PocoJsonSerializerStrategy.SerializeEnum( Enum p ) to

return p.ToString();

and changed the beginning of PocoJsonSerializerStrategy.DeserializeObject( object value, Type type ) to

object obj = null;
if ( value is string )
{
    string str = value as string;
    if ( type.IsEnum )
        obj = Enum.Parse( type, str );
    else if ( !string.IsNullOrEmpty( str ) && .....

This will serialize enums as strings and is able to deserialize them from strings.

@prabirshrestha
Copy link
Member

@JanWosnitza could you send a PR with unit tests.

@JanWosnitza
Copy link

@prabirshrestha I will definitely do it! But may take same time.. :) (I am not used to Git(Hub) and [Fags]Enums and nullable ones would be nice to (in case the enum value is not available))

@prabirshrestha
Copy link
Member

you could use ReflectionUtils to check for nullable

if (type == typeof(Guid) || (ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(Guid)))
                        obj = new Guid(str);

@jamesiq
Copy link

jamesiq commented Mar 10, 2013

I struggled to make this work as described, but was able to borrow from it after dropping the latest build into my project.

Starting around line 1285: I simply inserted part of the above solution at line 1301: as demonstrated below. Hopefully this helps someone!!! Thanks again rock stars of awesome sauce, -James

1285: [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
public virtual object DeserializeObject(object value, Type type)
{
if (type == null) throw new ArgumentNullException("type");
string str = value as string;
if (type == typeof(Guid) && string.IsNullOrEmpty(str))
return default(Guid);

        if (value == null)
            return null;

        object obj = null;
        if(str != null)
        {
            if (str.Length != 0) // We know it can't be null now.
            {

1301: if (type.IsEnum)
return Enum.Parse(type, str);

@prabirshrestha
Copy link
Member

would be great if you can send a PR with unit tests.

@agillesp
Copy link

I did this instead:

public class EnumSupportedStrategy : PocoJsonSerializerStrategy
{
    public override object DeserializeObject(object value, Type type)
    {
        object obj;
        if (type.IsEnum && value is string)
            obj = Enum.Parse(type, (string)value);
        else
            obj = base.DeserializeObject(value, type);
        return obj;
    }
}

@prabirshrestha
Copy link
Member

@agillesp does that handle nullables?

@agillesp
Copy link

Almost certainly not - I doubt the "type.IsEnum" will report true if it's a nullable. My usecase doesn't have any nullable enum properties to serialize so I didn't bother. However, it should be easy to fix. You'll have to do a little more inspection into the type and then handle a null "value" argument appropriately.

@prabirshrestha
Copy link
Member

if you can write a unit test and send us a pull request it would be great.

@agillesp
Copy link

Well, unfortunately, I'm not too plugged into github's workflow and am not even sure how to do a pull request. I guess I fork, add my code, then do something? Also, this is not a platform fix, this is an additional serialization policy; right now the onus is on the developer whether to use the EnumSupportedStrategy. Though I suppose I could fix PocoJsonSerializerStrategy directly.

@prabirshrestha
Copy link
Member

fork the repo and create a new branch. I would love this to go in PocoJsonSerializerStrategy. and It should work with the DataContract one too.

NancyFX has a good guidelines on contributing. https://github.com/NancyFx/Nancy/blob/master/CONTRIBUTING.md You might want to look there.

Also remember the unit tests. Try sending the PR to our "dev" branch if possible.

@agillesp
Copy link

Well I'm happy to give back when I can. Just like everyone else who's a developer I'm plenty busy. But if I find the time this weekend I'll give it a shot.

@JanWosnitza
Copy link

I had some thoughts on this issue again. In the case you don't know all possible (enum-)values, it would be best to deserialize the enum as a string and make a wrapping property that is able to indicate an unknown value. This would allow you to output the actual value even though you didn't know it exists but also have the convenience of an enum.

enum MyEnum
{
    _UnknownValue,
    Ok,
    Error1,
    Error2,
};

class DataClass
{
    // Serialized field
    public string State;

    // Wrapping field
    public MyEnum_State
    {
        get
        {
            MyEnumval;
            if ( Enum.TryParse( this.State, out val ) )
                return value;
            return MyEnum._UnknownValue;
        }
        set { this.State = value.ToSring(); }
    }
}

@prabirshrestha I would love to extend this at home, but unfortunately I only have the VS-Express version. Express does not support portable DLLs which is a problem because the UnitTest Project references the portable DLL-Project. Any ideas? :)

@prabirshrestha
Copy link
Member

@JanWosnitza try it with normal non-portable reference. I don't think there will be much difference. Before I merge, I can test if it works with portable lib.

@agillesp
Copy link

@JanWosnitza I really can't understand what you're driving at here? From the perspective of the deserializer, aren't ALL enum values unknown (it has no knowledge of your model)? Now if you're speaking about a case where a value exists in the serial string, say "FakeValue", and this doesn't exist in the enum:

public enum MyEnum { RealValue };

Is this what you're talking about? In this case, wouldn't it just be best to throw? - your model can't consume this value and I'd expect an exception.

@JanWosnitza
Copy link

@prabirshrestha k, will try so. Next week.. ;)

@agillesp yes, that was my intended situation (forgot to give an example with e.g. "UnexpectedError"). And yes an exception should be thrown if you deserialize the enum directly. Nevertheless if you want to know if a value has value1 or value2 and don't care with all other values, you really want to let the serializer finish and get your model returned. (Imagine a bad/wirred documented third party server, e.g. facebook gg) I think it depends on your case..

@jonnii
Copy link

jonnii commented Aug 1, 2013

I know this thread is seriously old, but if someone comes along and wants support for enums the following has worked for me:

    public class EnumSupportedStrategy : PocoJsonSerializerStrategy
    {
        protected override object SerializeEnum(Enum p)
        {
            return p.ToString();
        }

        public override object DeserializeObject(object value, Type type)
        {
            var stringValue = value as string;
            if (stringValue != null)
            {
                if (type.IsEnum)
                {
                    return Enum.Parse(type, stringValue);
                }

                if (ReflectionUtils.IsNullableType(type))
                {
                    var underlyingType = Nullable.GetUnderlyingType(type);
                    if (underlyingType.IsEnum)
                    {
                        return Enum.Parse(underlyingType, stringValue);
                    }
                }
            }

            return base.DeserializeObject(value, type);
        }
    }

@Kordonme
Copy link

Kordonme commented Oct 1, 2014

To repeat @jonnii. This is way too old now. But I managed to build enum support. I'm not really sure how to write the tests. Honestly, I only forked. Haven't opened sln yet. But is this fixed in the SimpleJson.cs? Is it still a wanted feature?

@prabirshrestha
Copy link
Member

@Kordonme send a PR for at least the SimpleJson.cs and I will have a look at it.

@jasonmead jasonmead linked a pull request Dec 1, 2014 that will close this issue
@lostmsu
Copy link

lostmsu commented Jun 5, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants