views:

748

answers:

4

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.

+1  A: 

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

Matthew Sposato
+5  A: 

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

Wyatt Barnett
I would like it to be more dynamic. So I can serialize either A, B or C, D.
alex2k8
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
A: 

What about the the "[NonSerialized()]" attribute tag?

    class Foo  
    {
        field A;

        [NonSerialized()]
        field B;

        [NonSerialized()]
        field C;

        field D;  
    }
TWith2Sugars
That works for binary serialization. The example given is Java script serialization. I'm not sure if it will work for that kind.
JaredPar
The equivalent attribute for the JavaScriptSerializer is [ScriptIgnore()].
Lck
+2  A: 

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.

IndianaJones