2

Given the following code:

public enum Pet
{
    Cat,
    Dog
}

public interface IOwner
{
    Pet Pet
    {
        get;
        set;
    }
}

public class Owner : IOwner
{
    public Pet Pet
    {
        get;
        set;
    }
}

The following tests fail:

[TestFixture]
public class ImpromptuInterfaceExample
{
    private Owner owner;
    private ExpandoObject dynamicOwner;

    [SetUp]
    public void SetUp()
    {
        owner = new Owner { Pet = Pet.Dog };
        string serializedOwner = JsonConvert.SerializeObject(owner);
        dynamicOwner = JsonConvert.DeserializeObject<ExpandoObject>(serializedOwner);
    }

    [Test]
    public void InvalidCastException()
    {
        var duckType = ImpromptuDictionary.Create<IOwner>(dynamicOwner);
        Assert.That(duckType.Pet, Is.EqualTo(owner.Pet)); // System.InvalidCastException : Invalid cast from 'System.Int64' to 'JsonSerializationDemo.Pet'.
    }

    [Test]
    public void RuntimeBinderException()
    {
        var duckType = dynamicOwner.ActLike<IOwner>();
        Assert.That(duckType.Pet, Is.EqualTo(owner.Pet)); // Microsoft.CSharp.RuntimeBinder.RuntimeBinderException : Cannot implicitly convert type 'long' to 'JsonSerializationDemo.Pet'. An explicit conversion exists (are you missing a cast?)
    }
}

Is there a way to properly resolve this problem?

Hannele
  • 9,301
  • 6
  • 48
  • 68
David Peden
  • 17,596
  • 6
  • 52
  • 72

2 Answers2

1

Your line:

 var duckType = ImpromptuDictionary.Create<IOwner>(dynamicOwner);

Should have worked but there was a bug with Enums specifically in ImpromptuInterface that is now fixed in version 6.0. ImpromptuDictionary tries several ways to coerce a type at runtime and was using the wrong one for Enums. So it works now.

jbtule
  • 31,383
  • 12
  • 95
  • 128
  • 6.0 definitely fixed the first failing test. The second failing test now fails with the following error: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException : Cannot implicitly convert type 'long' to 'Sandbox.ImpromptuInterfaceExample.Pet'. An explicit conversion exists (are you missing a cast?). Is this something that can be fixed on your end or is this simply an unsupported use of ActLike<>? – David Peden Aug 04 '12 at 03:00
  • I found that changing the original type from ExpandoObject to ImpromptuDictionary makes both tests pass. Thanks for the update to 6.0, Jay. – David Peden Aug 04 '12 at 03:13
  • Yeah ImpromptuDictionary does the extra work going above and beyound for converting, the interface proxy created by ActLike alone expects that the result matches the interface or can with an implict conversion. – jbtule Aug 04 '12 at 19:19
0

I think, the problem stems from fact, that Json serialiser serialises enums as numbers. But when it deserialises it into expando object, then it cannot possibly know, that the property is actualy an enum. This results in integer value in expando object.

This then confuses the impromptu-interface and causes exception in casting proxy. I think this could be resolved here, that the proxy builder would check, if the target type is enum, and use working coversion of in into enum. But you should take it to official page. I don't think SO can solve this problem.

Euphoric
  • 12,645
  • 1
  • 30
  • 44
  • I agree with your assessment. I have an email out to @JamesNK to see if he plans on adding TypeNameHandling support to his ExpandoObjectConverter. I think this would resolve the issue to where ImpromptuInterface could do the right thing. Patch 10926 (http://json.codeplex.com/SourceControl/list/patches) is "being evaluated" which, in part, apparently adds this capability. Fingers crossed... – David Peden May 06 '12 at 21:56