سؤال

أحاول إظهار الثوابت في عقود التعليمات البرمجية، واعتقدت أنني سأعطي مثالاً لقائمة مرتبة من السلاسل.إنه يحتفظ بمصفوفة داخليًا، مع مساحة احتياطية للإضافات وما إلى ذلك - تمامًا مثل List<T>, ، أساسًا.عندما يحتاج إلى إضافة عنصر، فإنه يقوم بإدراجه في المصفوفة، وما إلى ذلك.اعتقدت أن لدي ثلاثة ثوابت:

  • يجب أن يكون العد معقولا:غير سلبي وعلى الأكثر كبير مثل حجم المخزن المؤقت
  • يجب أن يكون كل شيء في الجزء غير المستخدم من المخزن المؤقت فارغًا
  • يجب أن يكون كل عنصر في الجزء المستخدم من المخزن المؤقت "كبيرًا" على الأقل مثل العنصر الذي يسبقه

والآن حاولت تنفيذ ذلك بهذه الطريقة:

[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));

وهذا أمر قبيح إلى حد ما، على الرغم من أنه يعمل.(إنها أفضل بكثير من محاولتي السابقة، انتبه.)

هل توقعاتي غير معقولة؟هل ثوابتي غير معقولة؟

(وسئل أيضا باسم أ سؤال في منتدى العقود المدونة.سأضيف أي إجابات ذات صلة هنا بنفسي.)

هل كانت مفيدة؟

المحلول

من صفحات MSDN (الأولية) يبدو أن عضو Contract.ForAll يمكنه مساعدتك في عقدي النطاق.الوثائق ليست واضحة جدًا بشأن وظيفتها بالرغم من ذلك.

//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));

نصائح أخرى

(سأقبل إجابة هينك، ولكن أعتقد أن الأمر يستحق إضافة هذا.)

تمت الإجابة على السؤال الآن على منتدى 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);
}

ربما أكتب هراء، لكن حتى في هذه الحالة سيكون لذلك قيمة تعليمية عندما يقول لي الجميع خطأ.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top