views:

88

answers:

4

Hello,

I've a simple class

[Serializable]
public class MyClass
{
  public String FirstName { get; set: }
  public String LastName { get; set: }

  //Bellow is what I would like to do
  //But, it's not working
  //I get an exception
  ContactDataContext db = new ContactDataContext();

  public void Save()
  {
   Contact contact = new Contact();
   contact.FirstName = FirstName;
   contact.LastName = LastName;

   db.Contacts.InsertOnSubmit(contact);
   db.SubmitChanges();
  }
}

I wanted to attach a Save method to the class so that I could call it on each object. When I introduced the above statement which contains ContactDataContext, I got the following error "In assembly ... PublicKeyToken=null' is not marked as serializable"

It's clear that the DataContext class is generated by the framework (). I checked and did not see where that class was marked serialize.

What can I do to overcome that? What's the rule when I'm not the author of a class? Just go ahead and mark the DataContext class as serializable, and pretend that everything will work?

Thanks for helping

A: 

I think you do need to decorate the base class, however, the DataContext auto generated classes are marked as partial. Have you tried doing something like:

[Serializable]
public partial class ContactDataContext
{
}

Not sure if it would work but its worth a try.

James
+1  A: 

The problem is that the db field gets serialized, while clearly it doesn't need to be serialized (it's instantiated once the object is created).

Therefore, you should decorate it with the NonSerialized attribute:

[NonSerialized] 
ContactDataContext db = new ContactDataContext();

[Update]

To make sure the db field is accesable after object initialization, you should use a lazy loading property and use this property instead of the field:

[NonSerialized] 
ContactDataContext db = null;

[NonSerialized] 
private ContactDataContext {
    get {
        if (db == null) {
            db = new ContactDataContext();
        }
        return db;
    }
    set {
        db = value;
    }
}

public void Save()
{
    Contact contact = new Contact();
    contact.FirstName = FirstName;
    contact.LastName = LastName;

    Db.Contacts.InsertOnSubmit(contact);
    Db.SubmitChanges();
}

[Update2]

You can serialize most objects, as long as it has a public parameterless constructor (or no constructor at all) and no properties/fields that cannot be serialized but require serializing. If the class itself is not marked as [Serializable], then you can do this yourself using a partial class. If the class has properties/fields that cannot be serialized, then you might achieve this by inheriting the class and overriding these properties/fields to decorate them as [NonSerialized].

Prutswonder
@PrutsWonder -- your answer allowed to get rid of the exception. Now I know that I need to think first before serializing, and I thank you for that. However, I still want to know what are the rules what it comes to class I did not write. Do I decorate that class with serialized attribute?
Richard77
Unfortunately, db.InsertOnSubmit is producing an "Object not set to an instance of an object" exception. Is there anything else to do?
Richard77
Updated the answer with a possible solution.
Prutswonder
@PrutsWonder -- Thanks a lot. It's working now. Before a let you go (accept your post as the answer to my question), tell me if I can serialize a class I didn't write.
Richard77
+1  A: 

You can create a surrogate that knows how to serialize the dodgy classes - see here for an example

thecoop
+2  A: 

It might be worth taking a step back and seeing if what you want to achieve is really valid.

Generally, a serializable class is used for data transport between two layers. It is more likely to be a simple class that only holds data.

It seems a little out of place for it to hold the ability to persist to a database. It is not likely that both ends of the pipe actually have access to the database, and it seems very unlikely that they would both have the ability to persist data.

I wonder if it's worth factoring the save out to a repository. So have a repository class that will accept the data transfer object, construct the database object and save it.

This will simplify your code and completely avoid the problem you're having. It will also greatly enhance testability.

Mac
@Mac: I like your advice
Richard77