Reputation: 2229
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, e.g. 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, e.g. using attributes?
Upvotes: 1
Views: 1988
Reputation: 84765
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
Upvotes: 2