简体   繁体   中英

Understanding code contracts for interfaces

I want to create a code contract for a certain interface, however I'm having a hard time believing that it is actually done this way.

[ContractClass(typeof(AsyncCacheProviderContract))]
public interface IAsyncCacheProvider {

    Task<bool> GetAsync<T>(string key, out T value);

}

[ContractClassFor(typeof(AsyncCacheProviderContract))]
internal abstract class AsyncCacheProviderContract : IAsyncCacheProvider {

    public Task<bool> GetAsync<T>(string key, out T value)
    {
        Contract.Requires(!String.IsNullOrEmpty(key));

        value = default(T);
        return Task.Factory.StartNew(() => false);
    }

}

The contract should ensure that 1) all classes implementing the interface require the argument key to be not null or empty as well as to 2) auto-generate the check into the build, eg similar to

public Task<bool> GetAsync<T>(string key, out T value) {
    if(String.IsNullOrEmpty(key))
        throw new ArgumentException //...
}

However in this particular case, it feels strange to me that I have to assign the out argument as well as return a dummy Task just to make the compiler happy. Is there no more straightforward way, eg using attributes?

It feels strange to me that I have to assign the out argument as well as return a dummy Task just to make the compiler happy.

You don't have to, if you throw an exception instead of return -ing from the method. Then you don't have to construct a return value, nor do you need to assign to the out parameter:

[ContractClassFor(typeof(IAsyncCacheProvider))] // note: there's a small change here!
sealed class AsyncCacheProviderContract : IAsyncCacheProvider
{
    public Task<bool> GetAsync<T>(string key, out T value)
    {
        Contract.Requires(!String.IsNullOrEmpty(key));
        throw new NotSupportedException(); // makes the compiler happy, too
    }

    private AsyncCacheProviderContract() { } // optional safeguard:
}                                            // prevent instantiation (see below)

In fact, this is semantically more correct than returning from the method. Why? Because no-one is meant to actually call these contract methods. They were never supposed to do any meaningful work, so they don't need to return any meaningful values. All that is required of your contract class is that it declares the contracts; the actual work is done somewhere else.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM