views:

51

answers:

5

Hi,

I'm working on a some project in C#, and I came across the following problem:

I have some data-type classes, for example a Person class, which keeps information about a person.

In addition, I have a DataManager class, which is responsible of managing the persons in my program. If you want to add, get, find, or remove a person, you would do it only through the DataManager class.

The problem is that I don't want anyone besides the DataManager class to be able to alter the Person objects. If someone calls DataManager.getPerson(int ID) for example, they would get a Person object and would be able to use the setter functions of that Person object to alter its contents (first name, last name, ID, etc.).

I want to avoid that. I want only the DataManager class to be able to alter the Person objects (through methods such as DataManager.changeFirstNameForPerson(int ID, string name)).

What is the best class structure that can achieve that?

Thanks, Malki.

+1  A: 

The first two things that spring to mind would be:

1 - Make the Person property setters protected and have DataManager derive from Person

2 - Make the Person property setters internal and put Person and DataManager in their own assembly

kekekela
A: 

Make the Person class immutable; that is, make all the fields on it readonly and provide only property getters, not setters. Pass values for all the fields into the constructor.

Tim Robinson
Not sure why this got down voted?
Tim Robinson
+1  A: 

If you declare your get/set accessors in the Person class with the internal keyword then only objects in the same assembly can access them. As long as you include the DataManager class in the same assembly it will have access and any code outside of the assembly will not.

TLiebe
A: 

One option is to refactor your existing Person class to be an inner class of DataManager (i.e. DataManager.Person) and then create a new Person class along the lines of:

public class Person
{
    private DataManager.Person person;

    public Person(Datamanager.Person person)
    {
        this.person = person
    }

    public int ID
    {
        get { return person.ID; }
    }

    ...
}

Then, in your DataManager class, you'd do something like:

public Person GetPerson(int id)
{
    DataManager.Person person = // get the person by ID
    return new Person(person);
}

Now external code has access to the read-only Person class but no way to get a reference to the read/write DataManager.Person.

Dave Kilian
+2  A: 

Well, you'll never be able to stop people from changing the values 100%. They could always just go through reflection.

But, from the API standpoint, you could make all the getters of your Person class public, adn all of the setters internal. As long as the Person and DataManager classes are in the same assembly, the DataManager will be able to access the setters fine, but other apps that reference the assembly cannot.

public class Person
{
    public string Fname { get; internal set; }
}


public class DataManager
{
    public void ChangeNameForPerson(int id, string fname)
    {
        Person p = Person.GetById(id);
        // Inside the same assembly.  Setter is accessible
        p.Fname = fname;
    }
}

Outside of the assembly, you'd have this:

Person p = DataManager.GetPerson(1);
p.Fname = "asdf"; // Compile time error
DataManager.ChangeNameForPerson(1, "asdf"); // Works fine
Samuel Meacham