Search code examples
c#genericscode-contracts

Using Code Contracts With Generic Interface With Type Condition


I would like to add code contracts to a generic interface using an abstract class, but where the type parameter is validated.

Here is an example of what I would like to do:

[ContractClass(typeof(ContractsForIRepository<,>))]
public interface IRepository<T, in TId> where T : IEntity
{
    T GetById(TId id);
    T Persist(T entity);
    void Remove(TId id);
}

[ContractClassFor(typeof(IRepository<,>))]
internal abstract class ContractsForIRepository<T, TId> : IRepository<T, TId>
{
    public T GetById(TId id)
    {
        Contract.Requires(id != null);
        return default(T);
    }

    public T Persist(T entity)
    {
        Contract.Requires(entity != null);
        return default(T);
    }

    public void Remove(TId id)
    {
        Contract.Requires(id != null);
    }
}

I can easily get it to work by dropping the condition:

  • public interface IRepository<T, in TId> where T : IEntity
  • public interface IRepository<T, in TId>

But I really want to keep this. Is it possible?


Solution

  • Okay, it is actually trivial - specify the same condition on the abstract class!

    Full example below.

    [ContractClass(typeof(ContractsForIRepository<,>))]
    public interface IRepository<T, in TId> where T : IEntity
    {
        T GetById(TId id);
        T Persist(T entity);
        void Remove(TId id);
    }
    
    [ContractClassFor(typeof(IRepository<,>))]
    internal abstract class ContractsForIRepository<T, TId> : IRepository<T, TId> where T : IEntity
    {
        public T GetById(TId id)
        {
            Contract.Requires(id != null);
            return default(T);
        }
    
        public T Persist(T entity)
        {
            Contract.Requires(entity != null);
            return default(T);
        }
    
        public void Remove(TId id)
        {
            Contract.Requires(id != null);
        }
    }