【问题标题】:C# enum DataMember changes its value in WCFC# enum DataMember 在 WCF 中更改其值
【发布时间】:2016-08-28 06:20:43
【问题描述】:

我有以下代码sn -p

[DataMember]
public StateEnum DeviceState
    {
        get
        {
            return _deviceState;
        }
        set
        {               

            if (IsArmed)
            {
                _deviceState = value;
            }
            else
            {
                _whileDisarmState = value;
            }              
        }
    }

当 IsArmed 是布尔值时,
并且 StateEnum 具有以下结构

    [DataContract]
public enum StateEnum
{
    [EnumMember]
    ERROR,
    [EnumMember]
    CONNECTED,
    [EnumMember]
    DISCONNECTED,
    [EnumMember]
    DISARMED,
    [EnumMember]
    ALARM,
    [EnumMember]
    WARNING,

}

我有一个调用服务器并获取对象列表的方法,其中 DeviceState 是它的成员之一。 当我在返回列表之前在服务器端中断时,其中一个对象具有 DeviceState = StateEnum.DISCONNECTED 值,
但是当我在客户端中断时,我对同一个对象有 StateEunm.ERROR 值。

我很确定问题出在 IsArmed 布尔值上。 尝试 DataMember 并没有帮助,以及将 [KnownType(typeof(StateEnum))] 添加到对象本身。

还有一件事,这个枚举在客户端是已知的,在添加这个 if 语句之前它工作得非常好。

更新

我会尝试用更多的代码 sn-ps 来解释我的逻辑,
虽然这是复杂的代码,但我不确定我能不能完整地描述它。

以下是相关的属性和私有成员:

[DataMember]
    public bool IsArmed
    {
        get { return _isArmed; }
        set { _isArmed = value; }
    }

public StateEnum WhileDisarmState
    {
        get { return _whileDisarmState; }
        set { _whileDisarmState = value; }
    }

#region Private Members

    private StateEnum _deviceState;
    private bool _isArmed;
    private StateEnum _whileDisarmState;

    #endregion

DeviceState & WhileDisarmState 在构造函数中获取它们的初始值:

IsArmed = true;    
WhileDisarmState = StateEnum.DISCONNECTED;
DeviceState = StateEnum.DISCONNECTED;

DeviceState 是客户端 UI 的关键部分,
撤防时显示为“无法访问”。 它仍然可以通过不同的方法从不同的代码区域更新 - 但我不想显示它,只需将其保存在其他地方 - 并在再次武装时显示最近的状态。
这就是我的“不对称”二传手的原因。
这是 Arm & Disarm 的实现(从客户端调用)

public virtual void Arm()
    {
        IsArmed = true;
        DeviceState = WhileDisarmState;
        IsUpdated = true;
    }

    public virtual void DisArm()
    {
        DeviceState = StateEnum.DISARMED;
        IsArmed = false;
        IsUpdated = true;
    }

我希望我能提供尽可能多的信息。
谢谢,
诺尔。

【问题讨论】:

  • bool 是在哪里定义的?它是否在列表完成并发送时被覆盖?我怀疑您需要展示更多代码(一个最小的、完整的、可验证的示例)
  • 感谢您的部分更新!无论如何,这种“它仍然可以通过不同的方法从不同的代码区域更新”可能是问题的原因:) 只需仔细检查客户端上的 IsArmed 和 WhileDisarmState 是否是您所期望的,或者尝试看看会发生什么服务器直到返回对象之前...

标签: c# wcf enums datamember


【解决方案1】:

首先,非常重要的一点是您必须将实现合同分开。

为您的 DeviceState 保留标准的 setter 和 getter,并根据您的 setter 的当前代码实现单独的 SetDeviceState 方法

并相应地将所有引用从 DeviceState = 更改为 SetDeviceState

之后,如果需要,如果您有可能构建和测试服务的“调试”版本,我建议您向对象添加一个 temporary TraceHelper 属性,例如每次更新 DeviceState 和 IsArmed 时以附加模式更新的简单字符串

并且可能还跟踪所有调用者方法...

这样您就可以更轻松地发现更新顺序逻辑中是否存在错误..

【讨论】:

    【解决方案2】:

    您看到这种情况是因为您的 getter 和 setter 不对称。

    似乎DISCONNECTED 的值被设置在_whileDisarmState 变量上,而_deviceState 变量的初始状态为default(StateEnum),恰好是ERROR

    要解决此问题,请将数据传输对象的 getter 和 setter 更改为对称。理想情况下,从它们中删除所有业务逻辑,例如注意IsArmed 状态。

    与其询问我应该更新这个成员还是其他成员,而是让设置者为我确定它。

    不过,该逻辑不属于 DTO。目前,对象的状态取决于设置属性的顺序。当控制您设置属性的顺序时,这对于业务对象可能没问题。但是,当 WCF 实现决定属性设置的顺序时,这对于数据传输对象是绝对不能接受的。

    例如,考虑传递一个已武装并已连接的对象。如果 WCF 先设置IsArmed,然后设置DeviceState,您最终会得到一个处于连接状态的武装对象(即一切都很好)。但是,如果 WCF 首先设置 DeviceState,您最终会得到一个处于错误状态的武装对象,并将 _whileDisarmState 设置为已连接。换句话说,您最终会在传输的另一端得到一个处于不同状态的对象,这正是您要解决的问题。

    【讨论】:

    • 我更新了我的问题。您的回答是正确的,但我这样做是为了在调用 setter DeviceState 时简化我的代码。与其问我应该更新这个成员还是其他成员,而是让 setter 为我确定它。
    猜你喜欢
    • 2013-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多