객체 불변의 코드에 얼마나 자유로울 수 있습니까?
-
05-07-2019 - |
문제
코드 계약에서 불변을 입증하려고 노력하고 있으며 정렬 된 문자열 목록의 예를 제시 할 것이라고 생각했습니다. 추가를위한 여분의 공간이있는 배열을 내부적으로 유지합니다. List<T>
, 기본적으로. 항목을 추가해야 할 때는 배열 등에 삽입됩니다. 나는 세 가지 불변분이 있다고 생각했습니다.
- 카운트는 합리적이어야합니다 : 부적절하지 않고 최대 버퍼 크기만큼 큽니다.
- 버퍼의 사용하지 않은 부분에있는 모든 것은 null이어야합니다.
- 버퍼의 중고 부분에있는 각 항목은 최소한 이전 항목만큼 "큰"이어야합니다.
이제 저는 이런 방식으로이를 구현하려고 노력했습니다.
[ContractInvariantMethod]
private void ObjectInvariant()
{
Contract.Invariant(count >= 0 && count <= buffer.Length);
for (int i = count; i < buffer.Length; i++)
{
Contract.Invariant(buffer[i] == null);
}
for (int i = 1; i < count; i++)
{
Contract.Invariant(string.Compare(buffer[i], buffer[i - 1]) >= 0);
}
}
안타깝게도, ccrewrite
루프를 엉망으로 만들고 있습니다.
사용자 문서에 따르면이 방법은 일련의 호출이어야한다고합니다. Contract.Invariant
. 코드를 이와 같은 것으로 다시 작성해야합니까?
Contract.Invariant(count >= 0 && count <= buffer.Length);
Contract.Invariant(Contract.ForAll
(count, buffer.Length, i => buffer[i] == null));
Contract.Invariant(Contract.ForAll
(1, count, i => string.Compare(buffer[i], buffer[i - 1]) >= 0));
작동하지만 다소 추악합니다. (이전 시도보다 훨씬 낫습니다.)
내 기대는 불합리합니까? 내 불변은 비합리적입니까?
(또한 물었다 Code Contracts Forum의 질문. 여기에 관련 답변을 직접 추가하겠습니다.)
해결책
(예비) MSDN 페이지에서 계약처럼 보입니다. 그래도 문서는 그 기능에 대해 그다지 명확하지 않습니다.
//untested
Contract.Invariant(Contract.ForAll(count, buffer.Length, i => buffer[i] == null));
Contract.Invariant(Contract.ForAll(1, count,
i => string.Compare(buffer[i], buffer[i - 1]) >= 0));
다른 팁
(나는 Henk의 대답을 받아 들일 것입니다. 그러나 이것을 추가 할 가치가 있다고 생각합니다.)
질문은 이제 대답되었습니다 MSDN 포럼, 그리고 상향은 첫 번째 형태입니다 그렇지 않습니다 일할 것으로 예상됩니다. 불변은 정말로 일련의 전화가 필요합니다. Contract.Invariant
, 그리고 그게 다야.
이로 인해 정적 검사기가 불변을 이해하고 시행하는 것이 더욱 실현 가능합니다.
이 제한은 단순히 모든 논리를 다른 회원에게 넣음으로써 우회 할 수 있습니다. IsValid
속성, 그런 다음 전화 :
Contract.Invariant(IsValid);
그것은 의심 할 여지없이 정적 검사기를 엉망으로 만들지 만, 어떤 경우에는 유용한 대안이 될 수 있습니다.
디자이너들이 바퀴를 조금 재창조하지 않습니까?
무엇이 잘못되었는지 좋은 늙었습니다
bool Invariant() const; // in C++, mimicking Eiffel
?
이제 C#에서 우리는 const를 가지고 있지 않지만 왜 당신은 단지 Invariant
기능
private bool Invariant()
{
// All the logic, function returns true if object is valid i.e. function
// simply will never return false, in the absence of a bug
}
// Good old invariant in C#, no special attributes, just a function
그런 다음 해당 기능 측면에서 코드 계약을 사용합니까?
[ContractInvariantMethod]
private void ObjectInvariant()
{
Contract.Invariant(Invariant() == true);
}
어쩌면 나는 말도 안되는 글을 쓰고 있지만, 그 경우에도 모든 사람이 나에게 잘못을 말할 때 약간의 교훈적인 가치가있을 것입니다.