C#: jak zaimplementować i użyć atrybutu NotNull i CanBeNull

Chcę, aby programiści i ja wiedzieli, że metoda nie chce null i jeśli wyślesz null do niej tak czy inaczej, wynik nie będzie ładny.

W bibliotekach dzielonych Lokad , w przestrzeni nazw Lokad.Quality, znajdują się NotNullAttribute iCanBeNullAttribute. Ale jak to działa? Spojrzałem na kod źródłowy tych dwóch atrybutów i wygląda to tak:
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Parameter |
                AttributeTargets.Property | AttributeTargets.Delegate |
                AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
[NoCodeCoverage]
public sealed class NotNullAttribute : Attribute
{
}

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Parameter |
                AttributeTargets.Property | AttributeTargets.Delegate |
                AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
[NoCodeCoverage]
public sealed class CanBeNullAttribute : Attribute
{
}

Dwie puste klasy dziedziczące z Attribute. Jak są one używane? Czy trzeba szukać dokumentacji xml i wiesz, że tam jest? Ponieważ próbowałem zarówno zrobić własną kopię atrybutu, jak i użyć wersji Lokad, ale kiedy próbowałem wysłać null bezpośrednio w, nie dostałem wiadomości. Ani od Resharp, ani od VS., czego się spodziewałem. Ale jak są one używane? Czy mogę jakoś zrobić VS generować ostrzeżenia dla mnie, jeśli Próbuję wysłać coś, co jest null tam? A może po prostu jest używany w jakimś frameworku testowym? Albo?

Author: Dan Neely, 2009-04-27

4 answers

W okresie średnioterminowym lepszym rozwiązaniem będą "umowy kodowe" (w 4.0). Są one już dostępne (z licencjami academic lub commercial ), ale będą bardziej zintegrowane w VS2010. Może to zapewnić zarówno analizę statyczną, jak i wsparcie dla środowiska uruchomieniowego.

(edit) przykład:

Contract.RequiresAlways( x != null );
To proste... silnik code contracts działa na poziomie IL, więc może to analizować i wyrzucać Ostrzeżenia/błędy z kodu wywołującego podczas kompilacji lub podczas wykonywania. Do tyłu zgodność, jeśli masz istniejący kod weryfikacyjny, możesz po prostu powiedzieć, gdzie kończy się sprawdzanie rozsądku, a to zrobi resztę:
if ( x == null ) throw new ArgumentNullException("x");
Contract.EndContractBlock();
 46
Author: Marc Gravell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-27 08:00:33

Można to zrobić za pomocą AOP, przy czym Porada sprawdza w czasie wykonywania, czy parametr metody jest równy null i czy dozwolone jest NULL. Zobacz PostSharp i Spring.NET dla AOP.

Jeśli chodzi o ReSharper, zobacz Annotated Framework :

Przeanalizowaliśmy dużą część biblioteki klas. NET Framework, a także NUnit Framework i dodaliśmy do niej adnotacje za pomocą zewnętrznych plików XML, używając zestawu niestandardowych atrybutów z JetBrains.Przypisy przestrzeń nazw, a konkretnie:

  • StringFormatMethodAttribute (dla metod, które przyjmują ciągi formatowania jako parametry)
  • InvokerParameterNameAttribute (dla metod z literalnymi argumentami łańcuchowymi, które powinny pasować do jednego z parametrów wywołujących)
  • AssertionMethodAttribute (for assertion methods)
  • AssertionConditionAttribute (dla parametrów warunkowych metod twierdzenia)
  • TerminatesProgramAttribute (dla metod, które kończą kontrolę flow)
  • CanBeNullAttribute (dla wartości, które mogą być null)
  • NotNullAttribute (dla wartości, które nie mogą być null)
 19
Author: Anton Gogolev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-27 07:43:18

Te adnotacje są dla ReSharper i są kopiowane z JetBrains.Przestrzeń nazw adnotacji. Framework może umieścić je we własnej przestrzeni nazw, jednak ReSharper nie odbierze tych adnotacji automatycznie - musisz powiedzieć ReSharper, aby używał niestandardowej przestrzeni nazw w oknie dialogowym Opcje. Po wybraniu nowej przestrzeni nazw, Analiza ReSharper wychwyci atrybuty i wyświetli podświetlenia i ostrzeżenia.

 6
Author: citizenmatt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-31 14:28:21

Jak wskazuje Anton Gogolev , atrybuty mogą być tworzone za pomocą PostSharp.(zauważ, że CodeContract używa statycznych wywołań metod wewnątrz ciała metody)

Aktualizacja luty 2013: Nowe wydanie 3.0 PostSharp (obecnie w wersji Beta) będzie wspierać Walidacja parametrów, pól i właściwości

1) Article validate-parameters-using-attributes has implementation of

Public class NotEmpty : ParameterAttribute

Klasa Publiczna NotNull: ParameterAttribute

[AttributeUsage (AttributeTargets.Parametr)]

Public abstract class ParameterAttribute: Attribute

{

public abstract void CheckParameter(ParameterInfo parameter, object value); 

}

Do przetwarzania atrybutów parametru wymagane jest również atrybut metody z aspektem granicy metody.

2) w komentarzu do artykułu znajdują się linki do bardzo podobnej implementacji dla NonNull / NonEmpty

[return: NonNull] public SomeObject SomeMethod ([NonNull] AnotherObject param1)      

Kod źródłowy znajduje się w Google code Torch / DesignByContract

3) inny bardziej skomplikowany przykład jest opisany w http://badecho.com/2011/11/validating-method-parameters-with-postsharp/

 3
Author: Michael Freidgeim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:09