2

I have a class with many methods and a private readonly bool field called _isLoaded with its coresponding property: public bool IsLoaded:

class MyClass
{
    readonly bool _isLoaded;
    public bool IsLoaded
    {
        get { return _isLoaded; }
    }

    public void Method1()
    {
        //does whatever
    }

    public void Method2()
    {
        //does another thing
    }

    public void Load()
    {
        //does a lot of things and then...
        _isLoaded = true;
    }
}

I know there are object invariant methods that assure that after invoking any public method, certain objects still remain in a consistent state. Like, if I added this to my class:

[ContractInvariantMethod]
void checkState()
{
    Contract.Invariant(!_isLoaded);
}

now, my problem is: is there a way to tell the runtime not to invoke the method annotated with ContractInvariantMethod for just one specific public method (in my case, Load), so I could be sure that only that one method would be changing the state of my field?

(Or some other way to achieve the same end)

Thanks.

Edit:
@Liel
Thanks a lot for the answer!
This pattern works perfectly when we have only one field to worry about. I also added this contract postcondition:

public abstract class BaseMyClass
{
    private bool _isLoaded;
    public bool IsLoaded
    {
        get { return _isLoaded; }
    }
    public virtual void Load()
    {
        Contract.Ensures(IsLoaded);
        _isLoaded = true;
    }
}

public class MyClass : BaseMyClass
{
    public override void Load()
    {
        //does a lot of things and then...
        base.Load();
    }
}

Unfortunately, the static checker isn't smart enough to figure out I have to call base.Load() to fulfill the postcondition. It suggests I could just Contract.Assume(IsLoaded)... Apparently, The static checker is far from perfect.

4

2 回答 2

1

如果我了解您想要实现的目标,您可以使用 Contract.OldValue() 构造:

public class MyClass
{
    bool _isLoaded;

    public bool IsLoaded
    {
        get { return _isLoaded; }
    }

    public void Method1()
    {
        Contract.Ensures(this._isLoaded == Contract.OldValue(this._isLoaded));
        //does whatever
        _isLoaded = false;
    }

    public void Method2()
    {
        Contract.Ensures(this._isLoaded == Contract.OldValue(this._isLoaded));
        //does another thing
    }

    public void Load()
    {
        //does a lot of things and then...
        _isLoaded = true;
    }
}

当你编译它时,你会得到以下警告:

CodeContracts: ensures unproven: this._isLoaded == Contract.OldValue(this._isLoaded)
于 2013-07-01T07:36:38.993 回答
0

您可以尝试以下方法:

public class BaseMyClass
{
    private bool _isLoaded;
    public bool IsLoaded
    {
        get { return _isLoaded; }
    }
    public virtual void Load()
    {
        _isLoaded = true;
    }
}

public class MyClass : BaseMyClass
{
    public void Method1()
    {
        //does whatever
    }

    public override void Load()
    {
        //does a lot of things and then...
        base.Load();
    }
}

这样您就可以IsLoaded从访问MyClass,并确保只有Load覆盖会更改_isLoaded属性。

于 2013-06-30T07:02:47.117 回答