简体   繁体   中英

C# Dependent properties, dependency on correct order of setter execution

I wonder how to deal with dependent properties in C#. I have following simplified classes (I'm using DevExpress XAF ):

public class Company
{
    public ContactMethods? PreferredContactMethod { get; set; }
    // Missing: Collection of Employees...
}

public class Employee
{
    private Company company;

    public Company Company
    {
        get
        {
            return this.company;
        }
        set
        {
            company = value;
            if (company != null && PreferredContactMethod == null)
            {
                PreferredContactMethod = company.PreferredContactMethod;
            }
        }
    }

    public ContactMethods? PreferredContactMethod { get; set; }
}

When assigning a Company to an Employee, I set the Employee.PreferredContactMethod to the PreferredContactMethod of the Company (just for convenience, can be changed later).


Update:

I want to use the Company.PreferredContactMethod just as a default value when initializing new Employees. Every Employee stores its own ContactMethod independently from the Company. Later changes to the Company.PreferredContactMethod shouldn't update the Employee.PreferredContactMethod. It is perfectly legal for the Employee.PreferredContactMethod to be null (eg if explicitly set be user).


Quite simple code and of course this is just working fine. But I think it violates Microsoft's Property Design Guidelines :

Do allow properties to be set in any order even if this results in a temporary invalid object state.

Company = A, PreferredContactMethod = null gives another result than PreferredContactMethod = null, Company = A .

I think I cannot rely on a 'correct' order of the property setters (eg if using Automapper/Reflection), How do you deal with such a situation? I think it's not uncommon.

Thank you!

You want to ensure the invariant that the Employee's has the same PreferredContactMethod as this Company himself, unless he has a specified PreferredContancMethod himself. One way, extending your solution, is to implement this is to update this value like this:

public class Employee
{
    private Company company;
    public Company Company
    {
        get { return this.company; }
        set
        {
            this.company = value;
            UpdateCompanyPreferredContactMethod();
        }
    }

    private ContactMethods? preferredContactMethod;
    public ContactMethods? PreferredContactMethod 
    {
        get { return this.preferredContactMethod; }
        set
        {
            this.preferredContactMethod = value;
            UpdateCompanyPreferredContactMethod();
        }
    }

    private void UpdateCompanyPreferredContactMethod()
    {
        if (PreferredContactMethod == null)
        {
            PreferredContactMethod = company != null ?company.PreferredContactMethod : null;
        }
    }
}

However, this solution is fragile, as you have to update this value every time you change either. Instead, I would actually do something like this:

public class Employee
{
    public Company Company { get; set; }

    private ContactMethods? preferredContactMethod;
    public ContactMethods? PreferredContactMethod 
    {
        get 
        { 
            if (this.preferredContactMethod != null)
            {
                return this.preferredContactMethod;
            }
            else if (this.Company != null)
            {
                return this.Company.PreferredContactMethod;
            }
            else
            {
                return null;
            }
        }
        set { this.preferredContactMethod = value; }
    }
}

You say you want to use the PreferredContactMethod as default value when initializing a new Employee. If this is the case, you should pass the Company to the constructor of the Employee, and set it then:

public Employee(Company company) {
    // Null checks as appropriate
    this.company = company;
    this.PreferredContactMethod = company.PreferredContactMethod;
}

If you also want to change the PreferredContactMethod the way you do, and your only concern is violating the design guidelines, then maybe use a method Employee.SetCompany to indicate that the operation has side effects in addition to just changing the Company property.

I think you need to assign it just before when saving the Employee object therefore any order gives the same result.

try this;

if (IsNewRecord && Company != null && PreferredContactMethod == null)
    PreferredContactMethod = Company.PreferredContactMethod;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM