5

Given such object:

Foo foo = new Foo
{
    A = "a",
    B = "b",
    C = "c",
    D = "d"
};

How can I serialize and deserialize only certain properties (e.g. A and D).

Original: 
  { A = "a", B = "b", C = "c", D = "d" }

Serialized:
  { A = "a", D = "d" }

Deserialized:
  { A = "a", B = null, C = null, D = "d" }

I have wrote some code using JavaScriptSerializer from System.Web.Extensions.dll:

public string Serialize<T>(T obj, Func<T, object> filter)
{
    return new JavaScriptSerializer().Serialize(filter(obj));
}

public T Deserialize<T>(string input)
{
    return new JavaScriptSerializer().Deserialize<T>(input);
}

void Test()
{
    var filter = new Func<Foo, object>(o => new { o.A, o.D });

    string serialized = Serialize(foo, filter);
    // {"A":"a","D":"d"}

    Foo deserialized = Deserialize<Foo>(serialized);
    // { A = "a", B = null, C = null, D = "d" }
}

But I would like the deserializer to work a bit differently:

Foo output = new Foo
{
    A = "1",
    B = "2",
    C = "3",
    D = "4"
};

Deserialize(output, serialized);
// { A = "a", B = "2", C = "3", D = "d" }

Any ideas?

Also, may be there are some better or existing alternatives available?

EDIT:

There was some suggestions to use attributes to specify serializable fields. I am looking for more dynamic solution. So I can serialize A, B and the next time C, D.

EDIT 2:

Any serialization solutions (JSON, XML, Binary, Yaml, ...) are fine.

alex2k8
  • 42,496
  • 57
  • 170
  • 221

4 Answers4

24

Pretty easy--just decorate the methods you wish to ignore with the [ScriptIgnore] attribute.

Jarrod Dixon
  • 15,727
  • 9
  • 60
  • 72
Wyatt Barnett
  • 15,573
  • 3
  • 34
  • 53
  • I would like it to be more dynamic. So I can serialize either A, B or C, D. – alex2k8 Jun 04 '09 at 12:44
  • 4
    Then you are looking at this from the wrong angle--the native Serialization is about serializing objects. Probably the best bet would be to create two objects--one for A and B, one for C and D, and then serialize either of them as appropriate. – Wyatt Barnett Jun 04 '09 at 15:43
5

I have done something similar myself with the Javascript Serializer in the past. In my case I only wanted to serialize nullable properties in the object that contained a value. I did this by using reflection, checking the property for a value and adding the property to a Dictionary e.g.

public static Dictionary<string,object> CollectFilledProperties(object instance)
{
    Dictionary<string,object> filledProperties = new Dictionary<string,object>();
    object data = null;

    PropertyInfo[] properties = instance.GetType().GetProperties();
    foreach (PropertyInfo property in properties)
    {
        data = property.GetValue(instance, null);

        if (IsNullable(property.PropertyType) && data == null)
        {
            // Nullable fields without a value i.e. (still null) are ignored.
            continue;
        }

        // Filled has data.
        filledProperties[property.Name] = data;
    }

    return filledProperties;
}

public static bool IsNullable(Type checkType)
{
    if (checkType.IsGenericType && checkType.GetGenericTypeDefinition() == typeof(Nullable<>))
    {
        // We are a nullable type - yipee.
        return true;
    }
    return false;
}

Then instead of serializing the original object you pass the dictionary and bob's your uncle.

Jarrod Dixon
  • 15,727
  • 9
  • 60
  • 72
IndianaJones
  • 66
  • 1
  • 1
3

There are attributes that can be applied to classes and/or properties that control serialization. Attributes that control serialization.

Matthew Sposato
  • 1,635
  • 1
  • 11
  • 13
1

What about the [NonSerialized()] attribute tag?

    class Foo  
    {
        field A;

        [NonSerialized()]
        field B;

        [NonSerialized()]
        field C;

        field D;  
    }
karel
  • 5,489
  • 46
  • 45
  • 50
TWith2Sugars
  • 3,384
  • 2
  • 26
  • 43
  • 1
    That works for binary serialization. The example given is Java script serialization. I'm not sure if it will work for that kind. – JaredPar Jun 04 '09 at 13:28
  • 6
    The equivalent attribute for the JavaScriptSerializer is [ScriptIgnore()]. – LorenzCK Aug 06 '09 at 14:44