C# Unproven确保结合接口引用另一个属性

C# Unproven确保结合接口引用另一个属性,c#,.net,code-contracts,C#,.net,Code Contracts,假设以下代码: [ContractClass(typeof(ICC4Contract))] public interface ICC4 { bool IsFooSet { get; } string Foo { get; } } public class CC4 : ICC4 { private string _foo; public bool IsFooSet { get { return Foo != null; } } public strin

假设以下代码:

[ContractClass(typeof(ICC4Contract))]
public interface ICC4
{
    bool IsFooSet { get; }
    string Foo { get; }
}

public class CC4 : ICC4
{
    private string _foo;

    public bool IsFooSet { get { return Foo != null; } }

    public string Foo { get { return _foo; } }
}

[ContractClassFor(typeof(ICC4))]
public abstract class ICC4Contract : ICC4
{
    public bool IsFooSet
    {
        get
        {
            Contract.Ensures((Contract.Result<bool>() && Foo != null)
                             || !Contract.Result<bool>());
            return false;
        }
    }

    public string Foo
    {
        get
        {
            Contract.Ensures((Contract.Result<string>() != null && IsFooSet)
                             || !IsFooSet);
            return null;
        }
    }
}
[ContractClass(类型(ICC4Contract))]
公共接口ICC4
{
bool-IsFooSet{get;}
字符串Foo{get;}
}
公共类CC4:ICC4
{
私人字符串(u foo),;
公共bool IsFooSet{get{return Foo!=null;}}
公共字符串Foo{get{return\u Foo;}}
}
[合同类别(类型(ICC4))]
公共抽象类ICC4Contract:ICC4
{
公共bool-IsFooSet
{
得到
{
Contract.surveures((Contract.Result()&&Foo!=null)
||!Contract.Result());
返回false;
}
}
公共字符串Foo
{
得到
{
Contract.surveures((Contract.Result()!=null&&IsFooSet)
||!IsFooSet);
返回null;
}
}
}
合同试图说明:

  • 如果
    Foo
    不是
    null
    ,则
    IsFooSet
    将返回
    true
  • Foo
    不返回
    null
    如果
    IsFooSet
    返回
    true
  • 这几乎奏效。
    然而,我在
    return\u foo
    ,因为检查器没有意识到
    Foo
    始终等于
    \u Foo

    Foo
    更改为带有
    private
    setter的自动属性会删除该警告,但我不想这样做(我不喜欢带有private setter的自动属性)

    在保留
    \u foo
    字段的同时,我必须对上述代码进行哪些更改才能使警告消失?

    以下操作不起作用:

  • IsFooSet
    更改为使用
    \u foo
    而不是
    foo
    。这将导致
    IsFooSet
    上出现额外的“未经验证”
  • 添加一个不变量
    Foo==\u Foo
    。这将导致隐式默认构造函数出现“未经验证的不变”。此外,在实际代码基础上,静态检查器的处理时间将更高
  • 添加
    Contract.sure(Contract.Result()==\u foo)
    Foo
    的getter,按照不会改变任何内容

  • 您可以使用短路来简化条件,这是出于某些原因:

    [ContractClassFor(typeof(ICC4))]
    public abstract class ICC4Contract : ICC4
    {
        public bool IsFooSet
        {
            get
            {
                Contract.Ensures(!Contract.Result<bool>() || Foo != null);
                return false;
            }
        }
    
        public string Foo
        {
            get
            {
                Contract.Ensures(!IsFooSet || Contract.Result<string>() != null);
                return null;
            }
        }
    }
    
    [ContractClassFor(typeof(ICC4))]
    公共抽象类ICC4Contract:ICC4
    {
    公共bool-IsFooSet
    {
    得到
    {
    Contract.Result(!Contract.Result()| | Foo!=null);
    返回false;
    }
    }
    公共字符串Foo
    {
    得到
    {
    Contract.Contract(!IsFooSet | | Contract.Result()!=null);
    返回null;
    }
    }
    }
    
    这对您的问题没有帮助,但我可以问您为什么不喜欢带有私有setter的自动属性吗?大多数情况下,这些属性都是类的不变量,也就是说,支持字段应设置为只读。对于自动属性,这是不可能的。实际上,我试图完全避免自动属性。原因如下。如果默认情况下将
    \u foo
    设置为空字符串,是否会将其删除?感觉问题更多的是
    \u foo
    的默认值将是
    null
    @MichaelPerrenoud:不,这不会改变任何东西。为什么要这样做?
    \u foo
    的默认值对已定义的契约没有影响。@DanielHilgarth,我当时的假设是编译器将拥有的唯一现实是违反契约的默认值
    \u foo