5

using System.Web.Script.Serialization.JavaScriptSerializer

can I deserialize into an immutable object somehow?

   public class Item
{
    public Uri ImageUri { get;private set; }
    public string Name { get; private set; }
    public Uri ItemPage { get;private set; }
    public decimal Retail { get;private set; }
    public int? Stock { get; private set; }
    public decimal Price { get; private set; }


    public Item(Uri imageUri, string name, Uri itemPage, decimal retail, int? stock, decimal price)
    {
        ImageUri = imageUri;
        Name = name;
        ItemPage = itemPage;
        Retail = retail;
        Stock = stock;
        Price = price;
    }
}

Constraints: I don't want a public empty constructor, I don't want to change everything to mutable, and I don't want to use xml instead of Json.

3
  • 1
    Note, this object is not truly immutable but is instead immutable by convention. A future developer could mistakenly edit this class in the future, mutate one of the fields and break other assumptions about immutability. It's far more declarative to make the fields readonly. This reduces the chance a future developer will accidentally break the implicit immutable contract Commented Nov 2, 2010 at 18:11
  • Did you get any answer to this? I have the same issue here: stackoverflow.com/questions/7360239/… Commented Sep 9, 2011 at 12:57
  • @DuffMan I don't recall =( Jared good point. Commented Sep 12, 2011 at 16:31

2 Answers 2

8

I had to find an answer for this, and since this is the first result on google, but it didn't give an example, I decided to share what I came up with (based upon the link provided by James Ellis-Jones.)

My situation was I needed a "Money" object to be immutable. My Money object needed an amount and a currency. Needs to be immutable because I'm using it as if it were the decimal value I'm replacing it with (math operations supported on like-currency values) and I needed to pass it around without worrying about whether I'm passing by reference or a copy of the thing.

So, I implemented the JavaScriptConverter here:

public class MoneyJsonConverter : JavaScriptConverter
{

    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    {
        if (dictionary == null)
            throw new ArgumentNullException("dictionary");

        if (type != typeof(Money))
            return null;

        var amount = Convert.ToDecimal(dictionary.TryGet("Amount"));
        var currency = (string)dictionary.TryGet("Currency");

        return new Money(currency, amount);
    }

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        var moneyAmount = obj as Money;
        if (moneyAmount == null)
            return new Dictionary<string, object>();

        var result = new Dictionary<string, object>
            {
                { "Amount", moneyAmount.Amount },
                { "Currency", moneyAmount.Currency },
            };
        return result;
    }

    public override IEnumerable<Type> SupportedTypes
    {
        get { return new ReadOnlyCollection<Type>(new List<Type>(new[] { typeof(Money) })); }
    }
}

Then I registered the converter with the JavaScriptSerializer via the web.config file:

<system.web.extensions>
    <scripting>
        <webServices>
            <jsonSerialization>
                <converters>
                    <add name="MoneyConverter" type="My.Namespace.MoneyJsonConverter, MyAssembly, Version=1.0.0.0, Culture=neutral"/>
                </converters>
            </jsonSerialization>
        </webServices>
    </scripting>
</system.web.extensions>

That's it! I did also decorate my class with a couple attributes, though:

[Serializable]
[Immutable]
public class Money
Sign up to request clarification or add additional context in comments.

1 Comment

What's the Immutable attribute? Is this yours?
0

JavaScriptSerializer provides a customisation API, you can create a class which inherits from JavaScriptConverter to specify how to build your Item class from a dictionary of then use the RegisterConverters method on a JavaScriptSerializer instance to register your custom converter.

definition of javascriptserializer.registerconverters

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.