通用接口上的代码契约问题

发布于 2025-01-02 08:14:19 字数 1556 浏览 0 评论 0原文

我遇到了涉及通用接口合同的问题。我有两个通用接口,每个接口都有一个方法,该方法有一个前提条件(Requires 契约)。第一个接口的契约按预期工作:前提条件被传播到实现类,并且接口方法被适当地修饰(通过代码契约编辑器扩展)。未检测到第二个接口的合约,但两个接口/合约对之间的代码几乎相同。

//
// Example working as expected
//

[ContractClass(typeof(IExporterContract<>))]
public interface IExporter<in TInput> 
    where TInput : class
{
    // Shows adornment "requires obj != null"; contracts propogate
    void Export(TInput obj);
}

[ContractClassFor(typeof(IExporter<>))]
abstract class IExporterContract<TInput> : IExporter<TInput>
    where TInput : class
{
    public void Export(TInput obj)
    {
        Contract.Requires(obj != null);
    }
}


// 
// Example with unexpected behavior
//

[ContractClass(typeof(IParserContract<>))]
public interface IParser<out TOutput>
    where TOutput : class
{
    // Workbook is Microsoft.Office.Interop.Excel.Workbook

    // Does not show adornment "requires workbook != null"; contracts do not propogate
    TOutput Parse(Workbook workbook);
}

[ContractClassFor(typeof(IParser<>))]
abstract class IParserContract<TOutput> : IParser<TOutput>
    where TOutput : class
{
    public TOutput Parse(Workbook workbook)
    {
        Contract.Requires(workbook != null);
        return default(TOutput);
    }
}  

值得注意的是,Microsoft.Office.Interop.* 中的任何接口都会导致此行为。使用任何其他类型,一切都会按预期进行。然而,我不知道这是为什么。

编辑:正如Porges指出的,合同正在编写(通过IL确认),所以这似乎特定于代码合同编辑器扩展。

I am experiencing an issue involving contracts for a generic interface. I have two generic interfaces, each with a single method which has a single precondition (Requires contract). The contract for the first interface works as expected: the precondition is propagated to implemenation classes, and the interface method is adorned appropriately (via the Code Contracts Editor Extension). The contract for the second interface is not detected, but the code is nearly identical between the two interface/contract pairs.

//
// Example working as expected
//

[ContractClass(typeof(IExporterContract<>))]
public interface IExporter<in TInput> 
    where TInput : class
{
    // Shows adornment "requires obj != null"; contracts propogate
    void Export(TInput obj);
}

[ContractClassFor(typeof(IExporter<>))]
abstract class IExporterContract<TInput> : IExporter<TInput>
    where TInput : class
{
    public void Export(TInput obj)
    {
        Contract.Requires(obj != null);
    }
}


// 
// Example with unexpected behavior
//

[ContractClass(typeof(IParserContract<>))]
public interface IParser<out TOutput>
    where TOutput : class
{
    // Workbook is Microsoft.Office.Interop.Excel.Workbook

    // Does not show adornment "requires workbook != null"; contracts do not propogate
    TOutput Parse(Workbook workbook);
}

[ContractClassFor(typeof(IParser<>))]
abstract class IParserContract<TOutput> : IParser<TOutput>
    where TOutput : class
{
    public TOutput Parse(Workbook workbook)
    {
        Contract.Requires(workbook != null);
        return default(TOutput);
    }
}  

Of note, any interface in Microsoft.Office.Interop.* causes this behavior. Using any other type, everything works as expected. I'm unaware of why this is, however.

EDIT: as Porges pointed out, the contracts are being written (confirmed via IL), so this seems to be specific to the Code Contracts Editor extension.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

没︽人懂的悲伤 2025-01-09 08:14:19

我无法复制这个。给定此代码(以及您的示例):

class Program
{
    static void Main(string[] args)
    {
        var g = new Bar();
        g.Parse(null);
        var f = new Foo();
        f.Export(null);
    }
}

public class Foo : IExporter<Foo>
{
    public void Export(Foo obj)
    {
    }
}
public class Bar : IParser<Bar>
{
    public Bar Parse(Workbook workbook)
    {
        return null;
    }
}

合约按预期传播(通过 Reflector 反编译):

public Bar Parse(Workbook workbook)
{
    __ContractsRuntime.Requires(workbook != null, null, "workbook != null");
    return null;
}

I can't replicate this. Given this code (along with your example):

class Program
{
    static void Main(string[] args)
    {
        var g = new Bar();
        g.Parse(null);
        var f = new Foo();
        f.Export(null);
    }
}

public class Foo : IExporter<Foo>
{
    public void Export(Foo obj)
    {
    }
}
public class Bar : IParser<Bar>
{
    public Bar Parse(Workbook workbook)
    {
        return null;
    }
}

The contract is propagated as expected (decompiled via Reflector):

public Bar Parse(Workbook workbook)
{
    __ContractsRuntime.Requires(workbook != null, null, "workbook != null");
    return null;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文