合同C#设计:如何保证方法和功能

| 我最近开始按合同使用设计。关于如何保证方法和功能,我有一些疑问。
public static void SaveAttachment(Outlook.MailItem _mailItem, string saveTo)
    {
        Contract.Requires<ArgumentNullException>(_mailItem != null);
        Contract.Requires(_mailItem.Attachments.Count > 0);
        Contract.Requires(!String.IsNullOrEmpty(saveTo));            

        string attachLink = \"<file://{0}>\";
        StringBuilder sBuilder = new StringBuilder();
        try
        {
            foreach (string fp in saveAllEmailAttachmentsThenReturnSavedFilePathList(emailAttachmentList(_mailItem), saveTo))
            {
                sBuilder.Append(String.Format(\"Attachment saved: \" + attachLink, fp) + Environment.NewLine);
            }
            _mailItem.Body = sBuilder.ToString() + _mailItem.Body;
            _mailItem.Save();                
        }
        catch (Exception ex)
        {
            LogErrorMessage(ex);
        }            
    }
如您所见,以上方法将保存电子邮件附件,并确保传入的邮件项不为null且具有附件。但是,我如何保证此方法将执行其应做的事情。 功能上:
public static List<Outlook.MailItem> SelectedMail(Outlook.Selection selectedItems)
    {
        Contract.Requires(selectedItems.Count > 0);
        Contract.Ensures(Contract.Result<List<Outlook.MailItem>>().Count > 0);

        List<Outlook.MailItem> selectedMails = new List<Outlook.MailItem>();
        foreach (object obj in selectedItems)
        {
            if (obj is Outlook.MailItem)
            {
                selectedMails.Add((Outlook.MailItem)obj);
            }
        }

        Contract.Assume(selectedMails.Count > 0);
        return selectedMails;
    }
如果selectedItem没有邮件项怎么办?如果我写合同,则确保以这种方式会导致所选电子邮件中没有附件的错误。 抱歉,我是这个范例的新手。我想学习它,所以我不必使用if-else编写安全的防护代码。     
已邀请:
对于您的特定情况,我看到两种可能性: 确保要求为假,并且对0计数结果有效。 您还有一个额外的运行时要求,不能合理地表达为“合同”,因为它不是静态检查器希望证明的内容,因此您不想声明它。在这种情况下,您可能只想在运行时检查条件并引发Exception。 如果您发现自己想将非常复杂的要求作为合同的一部分来表达(甚至引发异常),则可能需要重新考虑您的设计以及为什么存在这种复杂要求。您的方法的用户能否记住并理解要求?还有其他方法可以封装行为,以便更清楚地表达需求吗?     
带有
.Assume()
的代码可能不会发出警告。 但是,您需要一个
Assume()
(即副本),因为静态验证程序无法足够远地回溯到数据源中。假设您要在其中插入“外部”信息来承担责任。 只要保持.Requires处于活动状态,就可以了。假设存在有效数据,静态检查器将验证其余逻辑。 但是请注意,实际上我会做些不同:
    public static List<Outlook.MailItem> SelectedMail(Outlook.Selection selectedItems)
    {
        Contract.Requires(selectedItems != null);    //always a good idea
        Contract.Requires(selectedItems.Count > 0);

        // can\'t promise this
        // Contract.Ensures(Contract.Result<List<Outlook.MailItem>>().Count > 0);  

        List<Outlook.MailItem> selectedMails = new List<Outlook.MailItem>();
        foreach (object obj in selectedItems)
        {
            if (obj is Outlook.MailItem)
            {
                selectedMails.Add((Outlook.MailItem)obj);
            }
        }

        // and then w/o the promise we don\'t need this
        // Contract.Assume(selectedMails.Count > 0);
        return selectedMails;
    }


    void SomeMethod()
    {
       var selected = SelectedMail(...);
       if (selected.Count > 0)
          SaveAttachment(selected, \"file\")
       else
          // you need a plan here anyway

    }
这将在没有Assume()的情况下进行验证     
好吧,对于第二个代码片段,您可以尝试:
Contract.Requires(Contract.Exists(selectedItems, x => x is Outlook.MailItem));
编辑:Gah-如果
Outlook.Selection
实现
IEnumerable
而不是
IEnumerable<T>
,那将不起作用:( 我不确定静态编译器可以检查这种合同的程度,诚然... 顺便说一下,您的方法主体可以非常轻松地减小尺寸:
return selectedItems.OfType<Outlook.MailItem>().ToList();
LINQ不可爱吗? :) 我不太确定您在第一段代码中要保证的内容...老实说,我认为您无法真正表达“已保存”部分。     

要回复问题请先登录注册