将库用户警告到不一致的状态

时间:2009-03-12 18:40:41

标签: c# .net

在本机库上的托管包装器中,我必须完成某些操作,这些操作对于高级对象的用户应该被视为原子和一致的。但是,本机代码中的基础操作是原子的并且是单独一致的,但不是整体的。

// Simplistic look at the AddRange operation
void AddRange(IEnumerable<ChildType> range)
{
    foreach (var value in range)
    {
        this.NativeAdd(value);
    }
}

// Simplistic look at the Delete operation
void Delete(ParentType value)
{
    foreach (var child in value.Children)
    {
        this.NativeDelete(child);
    }

    this.NativeDelete(value);
}

如果Native代码存在错误,则所有Native操作都会失败并显示常见的异常类型:

void NativeDelete(ChildType child)
{
    StatusCode status = StatusCode.NoError;
    NativeMethods.DeleteChild(this.id, child.Id, out status);

    if (status != StatusCode.NoError)
    {
        throw new LibraryException(this, child, status);
    }
}

在高级AddRange和Delete例程中,我遇到了一些原生的Add或Delete调用已经完成的情况,但是其中一个调用出现了错误,其余的都没有完成。

更新:如果用户添加了7个项目并且在第7个项目上失败了,或者如果他们成功添加了6个项目,那么对于用户来说,磁盘上的实际文件看起来不会有任何不同。记录错误的唯一时间是在运行时。因此,如果用户未意识到状态不一致的可能性,他们可能无法确定基础文件是否有效。

我应该:

  1. 让LibraryException通过并向用户提供ParentType或ChildType对象可能处于不一致状态的文档
  2. 在InconsistentStateException中包装LibraryException,其中包含有关哪些对象可能处于不一致状态的信息
  3. 在重新抛出用户的异常(不是粉丝)之前,抓住LibraryException并尝试“手动”回滚所做的更改。
  4. 别的什么?

3 个答案:

答案 0 :(得分:2)

如果没有真正的两阶段提交支持(即事务管理器),那么

3就不可能实现。如果在那里发生错误,手动回滚只会导致更多的不一致状态。

我认为2是多余的。如果在父类型上调用方法(这是这些方法公开的方法),并且在抛出该异常时发生异常,则假设对象上的状态已损坏(除少数例外) 。通常,当发生这种情况时,除了扔掉它并使用具有一致状态的新对象之外,你不能对该对象做很多事情。

留下1,记录它。虽然您可能在2中提供了大量结构化信息,但如果对象处于不一致状态,您确实不想尝试修复该状态,因为您冒更大的风险更多。

答案 1 :(得分:1)

我喜欢你的第二个选择 -

这将提供一个更有意义的异常,您可以控制它。没有理由强迫你的最终用户理解一些奇怪的状态代码等。至少这样,很明显发生了什么以及为什么。

答案 2 :(得分:1)

如果我正确理解您的更新,则调用者可以做的就是将信息传递给最终用户,最终用户必须决定是接受状态还是回滚。

在这种情况下,(2):提供所有信息,以便调用者可以将信息传递给用户,或日志文件,或一些统计数据,而无需大量工作。

(1)如果对(2)没有信息差异,则可以,例如,知道哪个项目失败是无关紧要的。

(3)如果你不能期望在大部分时间里修复它是没有意义的,如果你有一点机会让它变得更糟,那就很危险了。

根据文件大小,您可以通过处理副本来进行准原子更改。至少,用户可能期望一种简单的方法来回滚到上一次保存。