Only allowing certain types to set a property

I have a class that I want to track the IsDirty property on, so that I know if the object has been modified or not, so that when the object is saved to the database I can simply ignore the save if no changes have been made.  If a change has been made (IsDirty == true), then I want to go ahead and update the database and set IsDirty back to false.  However, what I don’t want, is to let anyone modify the IsDirty property, I would rather make it readonly so that people can’t mess with it.

The problem that I’m having is how to implement this, because the object doesn’t handle its own database persistance.  The object gets handed off to another class that will do the appropriate database operations, so the object is little more than a strongly typed DTO.  So I want to allow that other class, lets call it the Persistor, to be able to set the DTO’s IsDirty property back to false, but nobody outside of the Persistor and the DTO should be able to modify the property.

I can only think of one way to implement a solution that behaves how I want:

  • Make the property read/write but inside the setter, do a runtime check of the class that is attempting to set the property, and if its not of a certain type, throw an exception.

Frankly, this solution sucks because its going to take a performance hit each time I set IsDirty from the reflection of checking the caller, and it sucks because there’s no compile time checking going on.  There’s got to be a better way to implement this, but I can’t think of anything, other than changing the overall architecture.  Thoughts?

12 Comments so far »

  1. jmiller said,

    Wrote on January 18, 2006 @ 10:05 am

    Could you change direction and go to a “Unit of Work” (http://www.martinfowler.com/eaaCatalog/unitOfWork.html) pattern and more the IsDirty tracking to a different class? Keeping track of IsDirty state inside of an entity class is a little icky IMO.

    You might put the IsDirty setter on a segregated interface that only the database mappers use.

    The reflection idea doesn’t sound prudent to me.

  2. Anonymous said,

    Wrote on January 18, 2006 @ 10:18 am

    Have you tried:

    class Persistor;

    class DTO
    {
    public:
    class Keytype {
    friend class Persistor;
    Keytype();
    };
    void MakeClean(DTO::Keytype) {}
    };

    class Persistor {
    public:
    void Clean(DTO& dtd) {
    dtd.MakeClean(DTO::Keytype());
    }
    };

    Now a Persistor can call MakeClean, but no one else can (unless a Persistor or DTO delegates a DTO::Keytype object to them)

    DTO d;
    Persistor p;

    p.Clean(d); // this succeeds

    d.MakeClean(DTO::Keytype()); // this fails at compile-time

  3. Anonymous said,

    Wrote on January 18, 2006 @ 10:19 am

    I’d use:

    public bool IsDirty
    {
    get { return _isDirty; }
    internal set { _isDirty = value; }
    }

    (C# 2.0 only). Now I’ve restricted the setter visibility to types inside the same assembly. This may be restrictive enough for you depending on where the Persistor and other types live….

  4. Anonymous said,

    Wrote on January 18, 2006 @ 10:45 am

    I second Scott’s suggestion of the internal setter; hopefully they share an assembly…

  5. breichelt said,

    Wrote on January 18, 2006 @ 11:08 am

    wow, lots of comments

    Scott & John: I didnt know that you could selectively place the internal keyword on getters and setters like that in .net 2.0. Unfortunately, this is .net 1.1, and, for that matter, the classes are not in the same assembly. The persistor is part of the common base assembly, and the dto is a business object, in another assembly. Good tidbit to know though.

    Jeremy: thats a good idea, one that I will explore

    Craig: I also like your suggestion, it seems pretty easy, I’ll have to see if it would be viable, may have to make a new interface, which is no big deal

  6. johnwood said,

    Wrote on January 18, 2006 @ 1:03 pm

    Ben,
    You can implement Scott’s suggestion in .Net 1.1 simply by having two methods to get and set the field rather than a property. Just make the setter method internal and the getter method public.

    John W

  7. Anonymous said,

    Wrote on January 18, 2006 @ 2:01 pm

    It’s hard to know for sure without knowing the code, but maybe something like this?:

    PersistanceClass: IPersistStuff
    {
    public void PersistMyClass(MyClass class);
    }

    MyClass
    {
    private bool isDirty;
    public void Persist(IPersistStuff persistStuff)
    {
    if (isDirty)
    persistStuff(this);
    isDirty =false;
    }
    }

  8. Anonymous said,

    Wrote on January 18, 2006 @ 2:05 pm

    Sorry, messed that up:

    PersistanceClass: IPersistStuff
    {
    public void PersistMyClass(MyClass class);
    }

    MyClass
    {
    private bool isDirty;
    public void Persist(IPersistStuff persistStuff)
    {
    if (isDirty)
    PersistMyClass(this);
    isDirty = false;
    }
    }

  9. Anonymous said,

    Wrote on January 18, 2006 @ 3:27 pm

    If you really want to do this with 1.1, have a look at StrongNameIdentityPermission.

    http://msmvps.com/blogs/manoj/archive/2004/10/20/16208.aspx

  10. Anonymous said,

    Wrote on January 18, 2006 @ 4:44 pm

    perhaps ….

    MyDatabaseClass {
    protected bool isDirty
    }

    MyDirtyDatabaseClass : MyDatabaseClass {
    public bool isDirty {
    get { return isDirty }
    set { isDirty = value}
    }
    }

    MyDatabaseClass MyDatabaseClassFactory() {
    return (MyDatabaseClass) new MyDirtyDatabaseClass();
    }

  11. Anonymous said,

    Wrote on January 18, 2006 @ 6:09 pm

    Of all the comments here, I agree with Jeremy D. Miller. I like the idea of having a seperate object - perhaps the persistor itself - keeping track of the isdirty. The easy way to implement this is to have the DTO raise a MemberChanged event whenever a Set is called, and your listener object sets the isdirty flag on its own. then when your persistor comes along, it reads the isdirty from the listener object to determine whether or not it needs to update that object to the database. Doing this allows you to control which object your persistor pays attention to, to get the isdirty flag.

  12. jdvolz said,

    Wrote on January 20, 2006 @ 2:36 am

    Could you just use the get portion of the property and then write accessor methods for the internal data of the data base object? Something like:

    public class MyDBObject
    {
    private bool isDirty = false;
    public bool IsDirty
    {
    return this.isDirty;
    }

    //modifiers
    public void SetValue(object someValue)
    {
    ….//set the value within the data structure and then…
    this.isDitry = true;
    }

    }

    This method assumes that you are creating a layer of abstraction in the object, and only allowing the object to alter the data that is internal to it (called encapsulation I believe). I believe this is how DataSets keep track of the state of rows contained within them.

Comment RSS · TrackBack URI

Leave a Comment

Name: (Required)

E-mail: (Required)

Website:

Enter my name (ben) in this box, so I know you're a human.

Comment: