2014-12-01 3 views
2

저는 Microsoft Code Contracts와 함께 조금씩 노력하고 있습니다. 지금은 어색한 사건을 발견했습니다. 제 질문은이 상황을 해결할 수있는 우아한 방법이 있습니까?코드로 작성된 인터페이스에 대한 계약

의 내가 다음과 같습니다 저장소에 대한 간단한 특성 인터페이스를 가지고 가정 해 봅시다 :

속성의 표시로
[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#에서 다중 상속이 허용되지 않으므로 위에서 언급 한 두 가지 계약 클래스를 다시 구현해야합니다. 이로 인해 계약서에 대한 코드를 복제해야하는 상황에 처하게됩니다. 그것에 대해 생각하십시오 - 이것은 가능한 모든 경우에 저에게 틀린 것처럼 보입니다.

어떻게해야합니까?

+0

@MatthewWatson이 정말 ICanDelete 나를 도움이되지 않습니다 (연결된 ITwo가 ICANAdd (IOne)를 구현하지 않는다고 가정 해 봅시다. 그것들은 별개의 비 관련 인터페이스이며 onl IEntityStore는 IEntityStore에 특정한 다른 메소드와 함께 두 가지를 모두 구현합니다. 질문을주의 깊게 읽으십시오. – xvdiff

+1

물론 도움이됩니다. 어떻게 할 수 있는지 정확히 보여주는 답을 추가하고 있습니다. –

+0

@MatthewWatson 나는 링크에 제공된 예제에만 초점을 맞추고 그 뒤에있는 일반적인 아이디어에는 초점을 맞추지 않았다. 당신이 제공 한 답변은 완벽하게 작동합니다. 감사합니다! (또한 대답으로 게시하기 위해서. 나는 당신에게 상상의 인터넷 포인트를 줄 수있다.) – xvdiff

답변

4

CodeContracts 컴파일 타임 rewriter는 모든 기본 인터페이스에 대한 계약을 자동으로 발견하여 사용합니다. 특정 예 (당신이 기본 인터페이스 '계약 중 하나를 반복 할 필요가 없습니다 어떻게주의, 그럼에도 불구하고 그들은 여전히 ​​작동)에 대한

:

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. 
     } 
    } 
} 
관련 문제