问题描述
|
我最近开始按合同使用设计。关于如何保证方法和功能,我有一些疑问。
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不可爱吗? :)
我不太确定您在第一段代码中要保证的内容...老实说,我认为您无法真正表达“已保存”部分。