分配 属性 时如何防止 get 访问器调用 set 访问器

How to prevent get accessor to call set accessor when assigning a property

适用于:.Net、C#、.Net 核心

问题描述:

这可能是 Edgecase,或者我做的事情完全错误。
我正在关注 Microsoft Documentation 以创建具有属性的 class。 Class 应该提供一个到活动目录的接口。

当我调用 get 访问器时,属性 可能尚未在我的程序中设置,因此 属性 应该从活动目录中拉出,设置为 class并返回。

为了节省资源,还没有设置的属性我只想拉。 问题是 Get Accessor 调用 Set Accessor 以便在我的程序中设置 属性。
Set 访问器本身然后尝试将“新”值推回活动目录,尽管我想从活动目录进行只读操作。

可重现代码:

这是这样一个 属性 的例子:

/// <summary>
/// sAMAccountName - the logon name. eg. "musterma1"
/// </summary>
public string LogonName
{
    get
    {
        // if the value is not set,pull it from active directory
        LogonName ??= GetProperty("sAMAccountName");// if null, pull value;
        return LogonName;
    }
    set
    {
        if (value != LogonName)
        {
            // if the value has changed, push it to active directory
            LogonName = value;
            SetProperty("sAMAccountName", LogonName);
        }
    }
}
// further properties here

/// <summary>
/// this function calls the corresponsing active directory function in order 
/// to populate a poperty of the given user
/// </summary>
/// <param name="property">which property to populate</param>
/// <param name="value">what value should the property have?</param>
private void SetProperty(string property, string value)
{
    ObjectProperties.SetProperty(property, value, this.DistinguishedName);
}
/// <summary>
/// this function calls the corresponsing active directory function in order 
/// to receive the current users property
/// </summary>
/// <param name="property">which property to poulate</param>
private string GetProperty(string property)
{
    return ObjectProperties.AttributeValuesSingleString("property", this.DistinguishedName);
}

我考虑先检查是否为空,如果 属性 当前为空,则只在程序中设置它,不要将其推送到活动目录。但是,如何分配新属性呢?这些值不会被推送:

set
{
    if (LogonName == null) LogonName = value;
    else if (value != LogonName)
    {
        // if the value has changed, push it to active directory
        LogonName = value;
        SetProperty("sAMAccountName", LogonName);
    }
}

问题:

你知道如何调用 get 访问器并在我的程序中设置 属性 而无需调用 set 访问器并立即将 属性 推回活动目录吗?

您应该创建名为 _logonName 的私有字段并使用它重写您的 Get\Set。例如:

private string _logonName;

public string LogonName
{
    get
    {
        // if the value is not set,pull it from active directory
        _logonName ??= GetProperty("sAMAccountName");// if null, pull value;
        return _logonName;
    }
    set
    {
        if (value != _logonName)
        {
            // if the value has changed, push it to active directory
            _logonName = value;
            SetProperty("sAMAccountName", _logonName);
        }
    }
}

个人建议设置前不要检查数值是否不同。使用您的代码的代码可以做到这一点,调用 Set 访问器总是会设置一些东西是有道理的。

我会改写如下

public string LogonName
{
    get
    {
        // if the value is not set,pull it from active directory
        LogonName ??= GetProperty("sAMAccountName");// if null, pull value;
        return LogonName;
    }
    set
    {
            // if the value has changed, push it to active directory
            LogonName = value;
            SetProperty("sAMAccountName", LogonName);
    }
}

如果您关心性能,那么在设置之前,请期待使用您的代码进行测试的任何内容。 即

if(class.logonName != newName) 
     class.logonName = newName;

也更难意外导致 Whosebug。