Skip to main content
Added if (organization == value) return;
Source Link
dbc
  • 451
  • 1
  • 5
  • 7
public class PersonCreatedEventArgs : EventArgs
{
    public readonly Person Person;
    public readonly Organization Organization;

    public PersonCreatedEventArgs(Person person, Organization organization)
    {
        this.Organization = organization;
        this.Person = person;
    }
}

public class Person
{
    public static event EventHandler<PersonCreatedEventArgs> PersonAdded;
    public static event EventHandler<PersonCreatedEventArgs> PersonRemoved;

    private Organization organization;
    private string name;

    public string Name { get { return name; } private set { name = value; }}

    public Organization Organization { 
        get { 
            return organization;
        }
        set {
            if (organization == value)
                return;
            if (organization != null && PersonRemoved != null)
                PersonRemoved(this, new PersonCreatedEventArgs(this, organization));
            organization = value;
            if (organization != null && PersonAdded != null)
                PersonAdded(this, new PersonCreatedEventArgs(this, organization));
        }
    }

    public Person(Organization organization, string name)
    {
        if (organization == null)
        {
            throw new ArgumentNullException("organization");
        }

        Name = name;
        Organization = organization;
    }
}

public class Organization
{
    static Organization()
    {
        Person.PersonAdded += Person_PersonAdded;
        Person.PersonRemoved += Person_PersonRemoved;
    }

    static void Person_PersonRemoved(object sender, PersonCreatedEventArgs e)
    {
        e.Organization._people.Remove(e.Person);
    }

    static void Person_PersonAdded(object sender, PersonCreatedEventArgs e)
    {
        e.Organization._people.Add(e.Person);
    }

    private readonly List<Person> _people = new List<Person>();

    public IEnumerable<Person> People
    {
        get { return _people.AsReadOnly(); }
    }
}
public class PersonCreatedEventArgs : EventArgs
{
    public readonly Person Person;
    public readonly Organization Organization;

    public PersonCreatedEventArgs(Person person, Organization organization)
    {
        this.Organization = organization;
        this.Person = person;
    }
}

public class Person
{
    public static event EventHandler<PersonCreatedEventArgs> PersonAdded;
    public static event EventHandler<PersonCreatedEventArgs> PersonRemoved;

    private Organization organization;
    private string name;

    public string Name { get { return name; } private set { name = value; }}

    public Organization Organization { 
        get { 
            return organization;
        }
        set {
            if (organization != null && PersonRemoved != null)
                PersonRemoved(this, new PersonCreatedEventArgs(this, organization));
            organization = value;
            if (organization != null && PersonAdded != null)
                PersonAdded(this, new PersonCreatedEventArgs(this, organization));
        }
    }

    public Person(Organization organization, string name)
    {
        if (organization == null)
        {
            throw new ArgumentNullException("organization");
        }

        Name = name;
        Organization = organization;
    }
}

public class Organization
{
    static Organization()
    {
        Person.PersonAdded += Person_PersonAdded;
        Person.PersonRemoved += Person_PersonRemoved;
    }

    static void Person_PersonRemoved(object sender, PersonCreatedEventArgs e)
    {
        e.Organization._people.Remove(e.Person);
    }

    static void Person_PersonAdded(object sender, PersonCreatedEventArgs e)
    {
        e.Organization._people.Add(e.Person);
    }

    private readonly List<Person> _people = new List<Person>();

    public IEnumerable<Person> People
    {
        get { return _people.AsReadOnly(); }
    }
}
public class PersonCreatedEventArgs : EventArgs
{
    public readonly Person Person;
    public readonly Organization Organization;

    public PersonCreatedEventArgs(Person person, Organization organization)
    {
        this.Organization = organization;
        this.Person = person;
    }
}

public class Person
{
    public static event EventHandler<PersonCreatedEventArgs> PersonAdded;
    public static event EventHandler<PersonCreatedEventArgs> PersonRemoved;

    private Organization organization;
    private string name;

    public string Name { get { return name; } private set { name = value; }}

    public Organization Organization { 
        get { 
            return organization;
        }
        set {
            if (organization == value)
                return;
            if (organization != null && PersonRemoved != null)
                PersonRemoved(this, new PersonCreatedEventArgs(this, organization));
            organization = value;
            if (organization != null && PersonAdded != null)
                PersonAdded(this, new PersonCreatedEventArgs(this, organization));
        }
    }

    public Person(Organization organization, string name)
    {
        if (organization == null)
        {
            throw new ArgumentNullException("organization");
        }

        Name = name;
        Organization = organization;
    }
}

public class Organization
{
    static Organization()
    {
        Person.PersonAdded += Person_PersonAdded;
        Person.PersonRemoved += Person_PersonRemoved;
    }

    static void Person_PersonRemoved(object sender, PersonCreatedEventArgs e)
    {
        e.Organization._people.Remove(e.Person);
    }

    static void Person_PersonAdded(object sender, PersonCreatedEventArgs e)
    {
        e.Organization._people.Add(e.Person);
    }

    private readonly List<Person> _people = new List<Person>();

    public IEnumerable<Person> People
    {
        get { return _people.AsReadOnly(); }
    }
}
Source Link
dbc
  • 451
  • 1
  • 5
  • 7

You can guarantee that the bi-directional association between the Person and Organization objects cannot be broken by code outside the classes themselves by using events:

public class PersonCreatedEventArgs : EventArgs
{
    public readonly Person Person;
    public readonly Organization Organization;

    public PersonCreatedEventArgs(Person person, Organization organization)
    {
        this.Organization = organization;
        this.Person = person;
    }
}

public class Person
{
    public static event EventHandler<PersonCreatedEventArgs> PersonAdded;
    public static event EventHandler<PersonCreatedEventArgs> PersonRemoved;

    private Organization organization;
    private string name;

    public string Name { get { return name; } private set { name = value; }}

    public Organization Organization { 
        get { 
            return organization;
        }
        set {
            if (organization != null && PersonRemoved != null)
                PersonRemoved(this, new PersonCreatedEventArgs(this, organization));
            organization = value;
            if (organization != null && PersonAdded != null)
                PersonAdded(this, new PersonCreatedEventArgs(this, organization));
        }
    }

    public Person(Organization organization, string name)
    {
        if (organization == null)
        {
            throw new ArgumentNullException("organization");
        }

        Name = name;
        Organization = organization;
    }
}

public class Organization
{
    static Organization()
    {
        Person.PersonAdded += Person_PersonAdded;
        Person.PersonRemoved += Person_PersonRemoved;
    }

    static void Person_PersonRemoved(object sender, PersonCreatedEventArgs e)
    {
        e.Organization._people.Remove(e.Person);
    }

    static void Person_PersonAdded(object sender, PersonCreatedEventArgs e)
    {
        e.Organization._people.Add(e.Person);
    }

    private readonly List<Person> _people = new List<Person>();

    public IEnumerable<Person> People
    {
        get { return _people.AsReadOnly(); }
    }
}

In this scheme, setting the Organization of a Person fires events notifying the Organization of the association.

Since the "PersonRemoved" and "PersonAdded" events can only be fired from within the Person class itself, a Person can only be constructed with a given Organization, and the "People" list is returned read-only, all code outside the two classes is prevented from damaging the bi-directional association. In practice you'll want to add some asserts in the events to make sure the data stays consistent (in case somebody does something nasty with reflection, or in case of serialization errors, or etc.)