Implementation of non-void interface Code Contracts - default(T) vs throw NotImplementedException

倾然丶 夕夏残阳落幕 提交于 2019-12-12 14:14:55

问题


This may be mostly a question of style but when defining code contracts for non-void interface members, which approach is best:

Interface:

[ContractClass(typeof(IFooContract))]
public interface IFoo
{
    object Bar();
}

Contract option 1:

[ContractClassFor(typeof(IFoo))]
public abstract class IFooContract : IFoo
{
    object IFoo.Bar()
    {
        Contract.Ensures(Contract.Result<object>() != null);
        throw new NotImplementedException();
    }
}

Contract option 2:

[ContractClassFor(typeof(IFoo))]
public abstract class IFooContract : IFoo
{
    object IFoo.Bar()
    {
        Contract.Ensures(Contract.Result<object>() != null);
        return default(T);
    }
}

Most of the literature I've seen tend towards option 2 but I feel that option 1 is better as it is clearer that this is purely about the contract (and option 2 is technically breaking the contract it just defined).

Are there any scenarios where option 2 is preferred over option 1?


回答1:


Throwing an exception is semantically more correct, because the contract class can no longer be invoked and used in a seemingly reasonable way; callers will be stopped and told about their error.

However, NotImplementedException does not seem to be the proper exception to throw: That exception usually marks a section of code (such as a method body) that has yet to be implemented. But a non-void contract method has been implemented; it just isn't meant to be called. Thus I would prefer an InvalidOperationException or a NotSupportedException.

(You could even throw a custom exception type, e.g. a NotMeantToBeCalledException.)




回答2:


This should be an entirely subjective (and academic) argument, given that the code in the ContractClassFor class should never be called, ever. :-). As you've hinted (via non-void), the exception or default route is only required for the class to compile and isn't relevant to the contracts contained in the methods.

Obviously the abstract class cannot be directly instantiated, however, you should reduce the visibility of the ContractClassFor class to internal to reduce the changes of it being accidentally subclassed.

Additionally, Jon Skeet goes further and adds a private parameterless constructor to prevent any chance of instantiation:

private IFooContract() { }

(And to answer your question indirectly, by further expressing the fact that this is a "special" contracts helper class working around the fact that the contracts can't be placed in the interface directly, a reader of your code will easily recognise it as such just ignore the default / exception compiler placebo)



来源:https://stackoverflow.com/questions/22239292/implementation-of-non-void-interface-code-contracts-defaultt-vs-throw-notimp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!