В наличии свойство с атрибутами и атрибуты на ацессорах:
class A
{
private int value;
[DebuggerHidden]
public int Value
{
[Pure]
get { return this.value; }
set { this.value = value; }
}
}
Конвертим в методы:
class A
{
private int value;
public void SetValue([DebuggerHidden] int value) { this.value = value; }
[DebuggerHidden]
public int GetValue() { return this.value; }
}
Не понятно как как относится свойство к аргументу Set-метода и куда подевался [PureAttribute]...
Думаю при наличии атрибутов на самом свойстве, надо глянуть на AttributeUsage свойств и по возможности (то есть при наличии флага AttributeTargets.Method) применить их на получаемые после рефакторинга метод(ы).
Обратный рефакторинг тоже не очень корректен с атрибутами:
[Pure]
public int GetValue()
{
return this.value;
}
Применяет атрибуты метода на свойство, а не на ацессор:
[Pure]
public int Value
{
get { return this.value; }
}
Ещё заметил, что конвертирование в авто-свойство:
public int Value
{
[Pure]
get { return this.value; }
[DebuggerHidden]
get { this.value = value; }
}
Немного корёжит форматирование:
public int Value { [Pure]
get; [DebuggerHidden]
set; }
Это всё мелочи, но они иногда досаждают, когда атрибуты достаточно важны (как тот же [Pure] из контрактов).
ReSharper 4.5 Full Edition build 4.5.1231.7 on 2009-04-08T16:10:26
Тут Contract.Requires() — всего лишь вызов статического метода, какая разница что туда передалось: true или false, разве это позволяет судить далее по коду о значении ссылки text? (на самом деле позволяет, но совершенно в иную сторону) В уйме мест теперь подчёркивание по этому поводу А на Debug.Assert() такой реакции нет, всё верно, хотя устроено внутри так же — просто вызов статического метода
Здравствуйте, Пельмешко, Вы писали:
П>Тут Contract.Requires() — всего лишь вызов статического метода, какая разница что туда передалось: true или false, разве это позволяет судить далее по коду о значении ссылки text? (на самом деле позволяет, но совершенно в иную сторону) В уйме мест теперь подчёркивание по этому поводу А на Debug.Assert() такой реакции нет, всё верно, хотя устроено внутри так же — просто вызов статического метода
Ну так 4-тый решарпер ничего про CodeContracts не знает.
... << RSDN@Home 1.2.0 alpha 4 rev. 1227 on Windows Vista 6.1.7100.0>>
П>Тут Contract.Requires() — всего лишь вызов статического метода, какая разница что туда передалось: true или false, разве это позволяет судить далее по коду о значении ссылки text? (на самом деле позволяет, но совершенно в иную сторону) В уйме мест теперь подчёркивание по этому поводу А на Debug.Assert() такой реакции нет, всё верно, хотя устроено внутри так же — просто вызов статического метода
РеШарпер ничего не знает что "Contract.Requires()" — это некоторый вариант ассерта. И, соответственно, видит что твою переменную сравнили с null — значит она может быть null
Следующую версию РеШарпера научим работать с код-контрактами...
С уважением, Евгений
JetBrains, Inc. "Develop with pleasure!"
Здравствуйте, AndrewVK, Вы писали: AVK>Ну так 4-тый решарпер ничего про CodeContracts не знает.
Если вникнуть в мой пост, то меня интерисовало поведение именно "ничего не знающего" о контрактах решарпера.
Здравствуйте, xvost, Вы писали: X>И, соответственно, видит что твою переменную сравнили с null — значит она может быть null
Спасибо, теперь понятно Интересная логика...
X>Следующую версию РеШарпера научим работать с код-контрактами...
Хорошо бы
Очень хочется много quick fix'ов на подобие:
if (value == null)
{
throw new ArgumentNullException("value");
}
Здравствуйте, xvost, Вы писали:
X>РеШарпер ничего не знает что "Contract.Requires()" — это некоторый вариант ассерта. И, соответственно, видит что твою переменную сравнили с null — значит она может быть null
Может быть имеет смысл добавить возможность пометки атрибутом собственных аналогичных методов?
... << RSDN@Home 1.2.0 alpha 4 rev. 1227 on Windows Vista 6.1.7100.0>>
Здравствуйте, xvost, Вы писали:
X>Здравствуйте, Пельмешко, Вы писали:
X>Спасибо. Очень ценно. X>Если будут еще идеи таких преобразований — пиши, с удовольствием сделаем
Я с удовольствием, идей полно, и не только преобразований
Столкнулся со следующим:
На методы-инварианты (помечаются атрибутом System.Diagnostics.Contracts.ContractInvariantMethodAttribute) необходимо реагировать как на [UsedImplicitly], иначе выделяет как неиспользуемый:
Можно предусмотреть такие Bad Practices касаемо инвариантов: 1. В методе-инварианте нельзя вызывать метод-инвариант из базового класса. 2. Метод-инваринт должен быть всегда private в sealed-классах, в остальных случаях protected. (реврайтер/верификатор сейчас выдают ошибку только в случае использования private в non sealed, остальное побоку, хотя делать инвариант публичным или internal видимым — кощунство какое-то). 3. Можно приделать соглашение об именовании, цитирую мануал:
A common name used for the invariant method is "ObjectInvariant".
Ещё просто жизненно необходима генерация класса-контракта для интерфейсов и абстрактных классов.
Например? для того чтобы для такого интерфейса описать контракт:
interface ISomeInterface
{
void SomeMethod(string x);
int OtherMethod(DateTime d);
int SomeProperty { get; set; }
}
Надо написать аж вот такую байду:
[ContractClass(typeof(ISomeInterfaceContract))]
interface ISomeInterface
{
string SomeMethod(string x);
int OtherMethod(DateTime d);
int SomeProperty { get; set; }
}
[ContractClassFor(typeof(ISomeInterface))]
sealed class ISomeInterfaceContract : ISomeInterface
{
string ISomeInterface.SomeMethod(string x)
{
return default(string);
}
int ISomeInterface.OtherMethod(DateTime d)
{
return default(int);
}
int ISomeInterface.SomeProperty
{
get
{
return default(int);
}
set
{
}
}
}
И уже там излагать пред/пост-условия...
То есть: два атрибута + sealed class, explicitly-реализующий исходный интерфейс, в каждом из методов с возвращаемым значением заглушки в виде return default(T); (всё это согласно мануалу CodeContracts) Для абстрактных классов всё то же самое, только override и класс не sealed, а abstract.
Каждый раз набивать всё это, даже с помощью решарпера уж больно гемморно...
Сейчас R# ругается на именование такого класса (префикс I), что понятно...
Но думаю для контрактного класса стоит делать исключение
До использования контрактов у меня код был покрыт обычными ассертами:
Debug.Assert(x > 0, "wtf?");
Совсем мелочь, но пока делал find & replace хотелось иметь quickfix "Convert to Contract.Assert":
Contract.Assert(x > 0, "wtf?");
А если ассерт в начале метода и завязан на параметрах, то это явно будущее предусловие, тогда было бы предпочтительнее предлагать "Convert to Contract.Requires":
Contract.Requires(x > 0, "wtf?");
Вообще контракты должны быть в методе строго в определённом порядке:
1. if-then-throw — обычные проверки могут распознаваться контрактами в целях совместимости. 2. Contract.Requires / Contract.Requires<TException> 3. Contract.Ensures 4. Contract.EnsuresOnThrow<TException> 5. Contract.EndContractBlock — необходимо отметить конец блока контрактов при наличии if-then-throw проверок, в остальных случаях считать за redundant.
Это надо бы как-нибудь учесть, а то просто верификатор (то есть уже после компиляции) бракует код, если последовательность не соблюдена...
Хотя бы при вставке новых контрактов учитывать порядок...
Для параметров методов можно сделать quickfix "Write precondition", аналогично для возвращаемых значений и out-параметров можно сделать "Write postcondition", вставляющие готовые snippets для нужного параметра / результата метода:
static string SomeMethod(string a, out int x)
{
Contract.Requires(a ...);
Contract.Ensures(Contract.Result<string>() ...);
Contract.Ensures(Contract.ValueAtReturn(out x) ...);
...
}
Причём Contract.Result<T>() и Contract.ValueAtReturn(out T) нельзя использовать больше нигде, кроме как внутри вызова Ensures().
Есть ещё Contract.OldValue<T>(e), у которого очень много нюансов, описанных в мануале...
Здравствуйте, Пельмешко, Вы писали:
П>На методы-инварианты (помечаются атрибутом System.Diagnostics.Contracts.ContractInvariantMethodAttribute) необходимо реагировать как на [UsedImplicitly], иначе выделяет как неиспользуемый:
Нужно пометить в External Annotations атрибут System.Diagnostics.Contracts.ContractInvariantMethodAttribute атрибутом MeansImplicitUse.
... << RSDN@Home 1.2.0 alpha 4 rev. 1227 on Windows Vista 6.1.7100.0>>
Здравствуйте, xvost, Вы писали: X>Все идеи занес в специальный список, буду изучать его, увязывать со всем остальным и т.д.
Хотелось бы добавить комментарий зачем нужно всё то, что упомянул в плане контроля неправильного использования контрактов
Так как сейчас контракты представляют реврайтер и верификатор, получающие готовую сборку из компилятора, то все ошибки (ну почти) связанные с правильным использованием контрактов будут выявлены только после компиляции, которая может быть достаточно продолжительной...
Поэтому было бы очень хорошо отлавливать некоторые глупости именно решарпером, это было бы большим подспорьем при покрытии кода контрактами.
Я думаю нынешних возможностей анализа вполне достаточно.
Фактически всякие Contract.Result<>() являлись бы контекстными ключевыми словами (как сейчас from/select/let/group из Linq), если бы С# когда-нибудь будет поддерживать синтаксис контрактов:
int Foo(string s)
requires s != null
ensures result > 0
{
...
}
Но сейчас Contract.Result<T>() можно написать везде в методе и получить неопределённое поведение...
Здравствуйте, Пельмешко, Вы писали:
П>Поэтому было бы очень хорошо отлавливать некоторые глупости именно решарпером, это было бы большим подспорьем при покрытии кода контрактами.
Это в общем-то понятно. Только в real-time проверить мы сможем не очень многое... Ведь же задача проверки контрактов эквивалентна проблеме останова, которая, как известно, не решается в рамках машины Тьюринга Но простые кнтракты связаные с NRE проверять ес-но будем
С уважением, Евгений
JetBrains, Inc. "Develop with pleasure!"
Здравствуйте, xvost, Вы писали:
X>Здравствуйте, Пельмешко, Вы писали:
П>>Поэтому было бы очень хорошо отлавливать некоторые глупости именно решарпером, это было бы большим подспорьем при покрытии кода контрактами.
X>Это в общем-то понятно. Только в real-time проверить мы сможем не очень многое... Ведь же задача проверки контрактов эквивалентна проблеме останова, которая, как известно, не решается в рамках машины Тьюринга Но простые кнтракты связаные с NRE проверять ес-но будем
Не не не, я совершенно про другое — про контроль некорректного использования методов System.Diagnostics.Contracts, не в правильном порядке, не в своём контексте и т.п.
А сами контракты проверять решарпером я ни в коем случае не стал бы, зачем изобретать второй верификатор?
Нынешних средств со стороны R# достаточно для поверхностного анализа. Для верификации контрактов — cccheck.exe.