2010-05-06 5 views
5

У меня есть немного кода со следующей логикой:Что делать при использовании Contract.Assert (true) и метод должен что-то вернуть?

//pseudo-code 
foreach (element in elementList) { 
    if (element is whatever) 
     return element; 
    } 
} 

В теории, всегда есть один элемент, который бы то ни было, так что этот метод не должно создавать никаких проблем. В любом случае, я поместил утверждение на конец метода просто чтобы быть уверенным:

//pseudo-code 
foreach (element in elementList) { 
    if (element is whatever) 
     return element; 
    } 
} 

Contract.Assert(false, "Invalid state!"); 

Проблема в том, что так как этот метод должен возвращать что-то, и компилятор не понимает, что утверждение нарушит выполнение программы. Прежде чем использовать Контракты, в таких ситуациях я использовал бросить исключение, которое решило проблему. Как бы вы справились с этим с помощью Contract.Assert()? Возврат null или default (element_type) после вызова Contract.Assert(), зная, что он никогда не будет вызван и не закрыт компилятор? Или есть другой более элегантный способ сделать это?

Благодаря

+0

Не значит 'Contract.Assert (ложный, "Invalid состояние!");'? –

+0

Да, да. : facep: –

ответ

2

Вы могли бы пойти с

var result = null; 
foreach (element in elementList) { 
    if (element is whatever) 
     result = element; 
     break; 
    } 
} 

Contract.Assert(result != null, "Invalid state!"); 
return result; 

Он вводит перерыв, но это выглядит чище вокруг возвращения.

Даже пылесос будет

return elementList.Where(e => e is whatever).First(); 

Редактировать как @devoured указал выше ударит весь список

очиститель без где

return elementList.First(e => e is whatever); 

конец редактирования

Это просто взрывается, если ничего не найдено.

Но если вы действительно хотите Assert это может быть

var results = elementList.Where(e => e is whatever); 
Contract.Assert(results.Count() == 1, "Boo"); 
return results.First(); 

но это будет перебирать весь список тоже.

+0

Об использовании LINQ's First, будет ли запущен весь элемент списка, или он перестанет искать больше элементов в тот момент, когда он найдет первый? –

+1

@devoured Я думаю, как я написал, он будет запускать весь список. Но, возможно, используя его как 'elementList.First (e => e is whatever)' (обратите внимание на отсутствие 'Where'), следует остановиться на первом. Но я не тестировал его –

+0

Oooooooops.Я обманул «Принять ответную кнопку» и проголосовал за вас. Вы должны отредактировать свой ответ, чтобы он менял голосование :( –

1

Я думаю, вам будет лучше с Contract.Requires (то есть предварительным условием), чем здесь Contract.Assert. Предварительным условием для вашего фрагмента является то, что elementList содержит хотя бы один элемент, где выполняется условие.

Вы должны быть откровенно об этом, а не полагаться на Assert(false), что требует от читателя понимания остальной функции и последующего контроля потока, чтобы определить ситуации, в которых достигнут Assert(false).

Так что, я бы переписать как:

//precondition (checked only in debug builds) 
Contract.Require(elementList.Where(e => e is whatever).Count > 0,"elementList requires at least one element meeting condition whatever"); 
//do work (throws in release builds, never reached in debug ones) 
return elementList.First(e => e is whatever); 
+0

-, поэтому вам придется перебирать список дважды ... и это не вишня сверху ... вы даже используете '.Count()> 0' (вызов свойства невозможен, поскольку возврат' .Where() 'is' IEnumerable ', и этот тип не имеет свойства' .Count', а скорее метод расширения ... 'Enumerable.Count()'), который нужно перебирать по всему результату - скорее используйте '.Any()' –

+0

Nope. Кто-то не понимает, как работают контракты. Всякий раз, когда скорость важна, мой ответ перебирается по списку не более одного раза. код более читабельный, облегчает отладку и служит подсказкой для оптимизатора. Он не выполняется в производственном коде. –

+0

Нет. Кто-то не понимает, как работает Linq (прочитайте http://stackoverflow.com/questions/305092/which-method-performs-better-any-vs-count-0) и что свойство 'Count' не существует на 'IEnumerable ' - тем не менее выполнение 'Contract.Require' является вопросом конфигурации (ака' Выполнение проверки выполнения времени выполнения': ** 'Full' **,' Pre и Post', ...). –