组合接口的代码协定
本文关键字:代码 接口 组合 | 更新日期: 2023-09-27 18:32:50
我正在使用Microsoft代码合约一段时间了,今天我偶然发现了一个尴尬的案例。我的问题是 - 有没有一种优雅的方法来解决这种情况?
假设我有一个仓库的简单特征接口,如下所示:
[ContractClass(typeof(CanAddContract)]
public interface ICanAdd {
void Add(object entity);
}
此属性中的约定如下所示:
[ContractClassFor(typeof(ICanAdd))]
internal abstract class CanAddContract {
public void Add(object entity) {
Contract.Requires(object != null); // guard against null argument
}
}
所以,现在我们有类似的实体删除特征
[ContractClass(typeof(CanDeleteContract))]
public interface ICanDelete {
void Delete(object entity);
}
。和合同...
[ContractClassFor(typeof(ICanDelete))]
internal abstract class CanDeleteContract {
public void Delete(object entity) {
Contract.Requires(entity != null); // guard against null argument
}
}
这没有错。但是由于接口表示存储库特征,因此它们用于组成存储库接口:
public interface IEntityStore : ICanAdd, ICanDelete {
void SomeOtherMethodThatNeedsAContract();
}
现在怎么办?当我想为此接口创建合约类时,我必须再次重新实现上述两个合约类,因为 C# 中不允许多重继承。这让我处于必须复制合约代码的情况。想想看 - 这对我来说似乎在每种可能的情况下都是错误的。
我能做些什么呢?
CodeContracts编译时重写器将自动发现并使用所有基接口的协定。
对于您的特定示例(请注意您不需要重复任何基本接口的合约,但它们仍然有效(:
using System;
using System.Diagnostics.Contracts;
namespace Demo
{
[ContractClass(typeof(CanAddContract))]
public interface ICanAdd
{
void Add(object entity);
}
[ContractClassFor(typeof (ICanAdd))]
internal abstract class CanAddContract: ICanAdd
{
public void Add(object entity)
{
Contract.Requires(entity != null);
}
}
[ContractClass(typeof(CanDeleteContract))]
public interface ICanDelete
{
void Delete(object entity);
}
[ContractClassFor(typeof(ICanDelete))]
internal abstract class CanDeleteContract: ICanDelete
{
public void Delete(object entity)
{
Contract.Requires(entity != null);
}
}
[ContractClass(typeof(EntityStoreContract))]
public interface IEntityStore: ICanAdd, ICanDelete
{
void SomeOtherMethodThatNeedsAContract(object entity);
}
// Note how we only specify the additional contract for SomeOtherMethodThatNeedsAContract().
// We do NOT need to repeat the contracts for ICanAdd and ICanDelete.
// These contracts are automatically inferred from the ICanAdd and ICanDelete contracts.
[ContractClassFor(typeof(IEntityStore))]
internal abstract class EntityStoreContract: IEntityStore
{
public void SomeOtherMethodThatNeedsAContract(object entity)
{
Contract.Requires(entity != null);
}
public abstract void Add(object entity);
public abstract void Delete(object entity);
}
public sealed class EntityStore: IEntityStore
{
public void Add(object entity)
{
}
public void Delete(object entity)
{
}
public void SomeOtherMethodThatNeedsAContract(object entity)
{
}
}
public static class Program
{
private static void Main()
{
var entityStore = new EntityStore();
entityStore.Add(null); // This will correctly give a code contracts exception.
}
}
}