Null durum statik analizine yönelik öznitelikler
Null yapılabilir etkin bir bağlamda derleyici, tüm başvuru türü değişkenlerinin null durumunu tespit etmek üzere kodun statik analizini yapar:
- Not-null: statik analiz, bir değişkenin null olmayan bir değere sahip olduğunu belirler.
- belki-null: statik analiz, bir değişkene null olmayan bir değer atandığını belirleyemiyor.
Bu durumlar, bir null değere başvurmaya, bir öğesine başvurmayabilmeniz durumunda derleyicinin uyarı sağlamasına imkan tanır System.NullReferenceException . Bu öznitelikler, derleyicinin bağımsız değişkenlerin ve dönüş değerlerinin durumuna göre null durumu , dönüş değerleri ve nesne üyeleri hakkında anlam bilgilerini sağlar. API 'niz Bu anlam bilgileriyle düzgün bir şekilde açıklandığında derleyici daha doğru uyarılar sağlar.
Bu makalede, her bir null yapılabilir başvuru türü özniteliği ve bunların nasıl kullanılacağı hakkında kısa bir açıklama sunulmaktadır.
Bir örnekle başlayalım. Imagine, bir kaynak dizesini almak için kitaplığınızda aşağıdaki apı 'ye sahip. Bu yöntem ilk olarak C# 8,0 ve Nullable ek açıklamalarıyla yazılır:
bool TryGetMessage(string key, out string message)
{
if (_messageMap.ContainsKey(key))
message = _messageMap[key];
else
message = null;
return message != null;
}
Yukarıdaki örnek, Try* .net 'teki tanıdık olan bir model izler. Bu API için iki başvuru parametresi vardır: key ve message . Bu API, bu parametrelerin null durumuyla ilgili aşağıdaki kurallara sahiptir:
- Çağıranlar
nulliçin bağımsız değişken olarak geçmemelidirkey. - Çağıranlar, değeri bağımsız değişkeni olan bir değişken geçirebilir
nullmessage. TryGetMessageYöntemi döndürürsetrue, değerimessagenull değildir. Dönüş değerifalse,değeri null ise,message.
Kuralı key C# 8,0 içinde succinctly ifade edilebilir: key null yapılamayan bir başvuru türü olmalıdır. messageParametresi daha karmaşıktır. Bağımsız değişken olarak bulunan bir değişkene izin verir null , ancak başarıyı, out bağımsız değişkenin olmadığı garantisini verir null . Bu senaryolar için beklentileri betimleyen daha zengin bir sözlük gerekir. NotNullWhenAşağıda açıklanan özniteliği, parametresi için kullanılan bağımsız değişken için null durumu açıklar message .
Not
Bu özniteliklerin eklenmesi, derleyiciye API 'nizin kuralları hakkında daha fazla bilgi verir. Kodu çağırma özelliği, null yapılabilir etkin bir bağlamda derlenirse, derleyici bu kuralları ihlal ettiklerinde çağıranları uyarır. Bu öznitelikler, uygulamanızda daha fazla denetim etkinleştirmez.
| Öznitelik | Kategori | Anlamı |
|---|---|---|
| AllowNull | Ön koşul | Null yapılamayan bir parametre, alan veya özellik null olabilir. |
| DisallowNull | Ön koşul | Null yapılabilir bir parametre, alan veya özellik asla null olmamalıdır. |
| MaybeNull | Son koşul | Null yapılamayan bir parametre, alan, özellik veya dönüş değeri null olabilir. |
| NotNull | Son koşul | Null yapılabilen bir parametre, alan, özellik veya dönüş değeri hiçbir şekilde null olmaz. |
| MaybeNullWhen | Koşullu Sonkoşul | Yöntem belirtilen değeri döndürdüğünde null yapılamayan bir bağımsız değişken null olabilir bool . |
| Notnullne zaman | Koşullu Sonkoşul | Yöntem belirtilen değeri döndürdüğünde null yapılabilir bir bağımsız değişken null olmaz bool . |
| NotNullIfNotNull | Koşullu Sonkoşul | Belirtilen parametre için bağımsız değişken null değilse, dönüş değeri, özellik veya bağımsız değişken null olamaz. |
| MemberNotNull | Yöntem ve özellik Yardımcısı yöntemleri | Yöntemin döndürdüğü belirtilen üye null olmaz. |
| Membernotnullne zaman | Yöntem ve özellik Yardımcısı yöntemleri | Yöntem belirtilen değeri döndürdüğünde listelenen üye null olmaz bool . |
| Yok et | Erişilemeyen kod | Bir yöntem veya özellik hiçbir şekilde döndürmez. Diğer bir deyişle, her zaman bir özel durum oluşturur. |
| Yok | Erişilemeyen kod | İlişkili parametre belirtilen değere sahipse bu yöntem veya özellik hiçbir şekilde döndürmez bool . |
Yukarıdaki açıklamalar, her bir özniteliğin yaptığı işe yönelik hızlı bir başvurudur. Aşağıdaki bölümlerde bu özniteliklerin davranışı ve anlamı daha ayrıntılı olarak açıklanır.
Ön koşullar: AllowNull ve DisallowNull
nullMakul bir varsayılan değere sahip olduğu için hiçbir süre döndürülmediği bir okuma/yazma özelliği düşünün. Çağıranlar null , bu varsayılan değere ayarlarken ayarlanan erişimciye geçer. Örneğin, bir sohbet odasında ekran adı isteyen bir mesajlaşma sistemi düşünün. Hiçbiri sağlanmazsa, sistem rastgele bir ad üretir:
public string ScreenName
{
get => _screenName;
set => _screenName = value ?? GenerateRandomScreenName();
}
private string _screenName;
Önceki kodu null olabilir bir zorunluluvou bağlamında derlerken her şey iyidir. Null yapılabilir başvuru türlerini etkinleştirdikten sonra, ScreenName özelliği null yapılamayan bir başvuru haline gelir. Bu, erişimci için doğrudur get : hiçbir şekilde döndürmez null . Çağıranlar için döndürülen özelliği denetmek zorunda değildir null . Ancak şimdi özelliği null bir uyarı oluşturacak şekilde ayarlanıyor. Bu tür bir kodu desteklemek için, System.Diagnostics.CodeAnalysis.AllowNullAttribute aşağıdaki kodda gösterildiği gibi özniteliğini özelliği ekleyin:
[AllowNull]
public string ScreenName
{
get => _screenName;
set => _screenName = value ?? GenerateRandomScreenName();
}
private string _screenName = GenerateRandomScreenName();
Bu using System.Diagnostics.CodeAnalysis makalede ele alınan bu ve diğer özniteliklerin kullanılması için bir yönerge eklemeniz gerekebilir. Özniteliği, erişimciye değil, özelliğine uygulanır set . AllowNullÖznitelik, ön koşulları belirtir ve yalnızca bağımsız değişkenler için geçerlidir. getErişimcinin dönüş değeri vardır, ancak hiçbir parametre yoktur. Bu nedenle, AllowNull öznitelik yalnızca erişimci için geçerlidir set .
Yukarıdaki örnekte, AllowNull bir bağımsız değişkende özniteliği eklenirken ne aranacağı gösterilmektedir:
- Bu değişken için genel sözleşme bunun olmaması
null, bu nedenle null atanamaz bir başvuru türü istemeniz gerekir. - Bir çağıranın bağımsız değişken olarak geçmesi için senaryolar vardır
null, ancak en sık kullanılan kullanım değildir.
Çoğu kez bu özniteliğe özellikler, veya in , out ve bağımsız değişkenler için ihtiyaç duyarsınız ref . AllowNullÖzniteliği genellikle null olmayan ancak önkoşul olarak izin vermeniz gereken en iyi seçenektir null .
Kullanma senaryolarıyla karşıtlık DisallowNull : Bu özniteliği, null yapılabilir bir başvuru türü bağımsız değişkeninin olmaması gerektiğini belirtmek için kullanırsınız null . nullVarsayılan değer olan, ancak istemciler yalnızca null olmayan bir değere ayarlayabileceği bir özelliği düşünün. Aşağıdaki kodu inceleyin:
public string ReviewComment
{
get => _comment;
set => _comment = value ?? throw new ArgumentNullException(nameof(value), "Cannot set to null");
}
string _comment;
Önceki kod, tasarımınızı ifade etmenin en iyi yoludur ReviewComment null , ancak olarak ayarlanamaz null . Bu kod null yapılabilir olduğunda, bu kavramı kullanarak çağıranlara daha net bir şekilde ifade edebilirsiniz System.Diagnostics.CodeAnalysis.DisallowNullAttribute :
[DisallowNull]
public string? ReviewComment
{
get => _comment;
set => _comment = value ?? throw new ArgumentNullException(nameof(value), "Cannot set to null");
}
string? _comment;
Null yapılabilir bir bağlamda, ReviewComment get erişimci varsayılan değerini döndürebilir null . Derleyici, erişim öncesinde denetlenmesi gerektiğini uyarır. Buna ek olarak, arayanlara açıkça ayarlanmaması durumunda bile arayanlara uyarır null null . DisallowNullÖznitelik bir ön koşul da belirtir, get erişimciyi etkilemez. DisallowNullAşağıdaki özellikleri gözlemlediğiniz zaman özniteliğini kullanabilirsiniz:
- Değişken
null, genellikle ilk örneği oluşturulduğunda temel senaryolarda olabilir. - Değişken açıkça olarak ayarlanmamalıdır
null.
Bu durumlar, başlangıçta null yükümlülüğü oluşturulan kodda ortaktır. Nesne özelliklerinin iki ayrı başlatma işlemi olarak ayarlanmış olması olabilir. Bazı özelliklerin bazı zaman uyumsuz çalışma tamamlandıktan sonra ayarlanmış olması olabilir.
AllowNullVe DisallowNull öznitelikleri, değişkenlerde önkoşulların Bu değişkenlerde null yapılabilir ek açıklamalarıyla eşleşmeyebilir belirtmenize olanak tanır. Bunlar, API 'nizin özellikleri hakkında daha ayrıntılı bilgi sağlar. Bu ek bilgiler, arayanların API 'nizi doğru şekilde kullanmasına yardımcı olur. Aşağıdaki öznitelikleri kullanarak önkoşulları belirtdüğünü unutmayın:
- AllowNull: null yapılamayan bir bağımsız değişken null olabilir.
- Disallownull: null olabilen bir bağımsız değişken asla null olmamalıdır.
Postconditions: MaybeNull ve NotNull
Aşağıdaki imzaya sahip bir yönteminiz olduğunu varsayalım:
public Customer FindCustomer(string lastName, string firstName)
Aranan ad bulunamadığı zaman döndürmek için bunun gibi bir yöntem yazmış oluk null . nullAçıkça kaydın bulunamadığını gösterir. Bu örnekte, büyük olasılıkla ' dan ' a dönüş türünü değiştirirsiniz Customer Customer? . Dönüş değerini null yapılabilir bir başvuru türü olarak bildirmek, bu API 'nin amacını açıkça belirtir:
public Customer? FindCustomer(string lastName, string firstName)
Genel türler kapsamında yer alan nedenlerden dolayı, TEKNIĞIN API 'niz ile eşleşen statik analizi oluşturmayabilir. Benzer bir kalıbı izleyen genel bir yönteminiz olabilir:
public T Find<T>(IEnumerable<T> sequence, Func<T, bool> predicate)
Yöntemi, null Aranan öğe bulunamadığında döndürür. Yöntemi, null MaybeNull Return yöntemine ek açıklama eklenerek bir öğe bulunamadığında, yöntemin döndürdüğünü açıklığa kavuşturmanıza olanak sağlayabilir:
[return: MaybeNull]
public T Find<T>(IEnumerable<T> sequence, Func<T, bool> predicate)
Yukarıdaki kod, arayanlara dönüş değerinin gerçekten null olabileceğini bildirir . Ayrıca, bir null tür null değer atanamaz olsa da yöntemin bir ifadeyi döndüremediğini derleyiciye bildirir. Tür parametresinin bir örneğini döndüren genel bir yönteminiz varsa, T özniteliğini kullanarak hiçbir zaman döndürdüğünü ifade edebilirsiniz null NotNull .
Bir dönüş değeri veya bağımsız değişken, tür null olabilen bir başvuru türü olsa da null olamaz. Aşağıdaki yöntem, ilk bağımsız değişkeni ise oluşturan bir yardımcı yöntemdir null :
public static void ThrowWhenNull(object value, string valueExpression = "")
{
if (value is null) throw new ArgumentNullException(nameof(value), valueExpression);
}
Bu yordamı aşağıdaki şekilde çağırabilirsiniz:
public static void LogMessage(string? message)
{
ThrowWhenNull(message, $"{nameof(message)} must not be null");
Console.WriteLine(message.Length);
}
Null başvuru türlerini etkinleştirdikten sonra, önceki kodun uyarı olmadan derlendiğinden emin olmak istersiniz. Yöntemi döndürüldüğünde, value parametresinin null olmaması garanti edilir. Ancak, ThrowWhenNull bir null başvurusuyla çağırmak kabul edilebilir. valueNull yapılabilir bir başvuru türü yapabilir ve NotNull parametre bildirimine son koşulu ekleyebilirsiniz:
public static void ThrowWhenNull([NotNull] object? value, string valueExpression = "")
{
_ = value ?? throw new ArgumentNullException(nameof(value), valueExpression);
// other logic elided
Yukarıdaki kod, mevcut sözleşmeyi açık bir şekilde ifade eder: çağıranlar değere sahip bir değişken geçirebilir null , ancak yöntem özel durum oluşturmadan bağımsız değişkeni hiçbir şekilde null olmaz.
Aşağıdaki öznitelikleri kullanarak koşulsuz Sonkoşulları belirtirsiniz:
- MaybeNull: null yapılamayan bir dönüş değeri null olabilir.
- NotNull: null olabilen bir dönüş değeri hiçbir şekilde null olmaz.
Koşullu koşul sonrası: NotNullWhen , MaybeNullWhen ve NotNullIfNotNull
Büyük olasılıkla yöntemiyle ilgili bilgi sahibisiniz string String.IsNullOrEmpty(String) . Bu yöntem true , bağımsız değişken null veya boş bir dize olduğunda döndürür. Bu bir null denetim biçimidir: çağıranların null olması gerekmez; yöntemin döndürdüğü bağımsız değişkeni kontrol edin false . Bu null yapılabilir bir yöntemi gibi bir yöntem oluşturmak için bağımsız değişkenini null atanabilir bir başvuru türüne ayarlarsınız ve NotNullWhen özniteliği ekleyebilirsiniz:
bool IsNullOrEmpty([NotNullWhen(false)] string? value)
Bu, derleyiciye dönüş değerinin null denetimleri gerektirmeyen herhangi bir kod olduğunu bildirir false . Özniteliğin eklenmesi, derleyicinin statik analizini, IsNullOrEmpty gerekli null denetimini yerine getiren bildirir: döndüğünde false bağımsız değişken değildir null .
string? userInput = GetUserInput();
if (!string.IsNullOrEmpty(userInput))
{
int messageLength = userInput.Length; // no null check needed.
}
// null check needed on userInput here.
String.IsNullOrEmpty(String)Yöntemi, .NET Core 3,0 için yukarıda gösterildiği gibi açıklanacaktır. Kod tabanınızda, null değerler için nesnelerin durumunu kontrol eden benzer yöntemlere sahip olabilirsiniz. Derleyici özel null denetim yöntemlerini tanımaz ve ek açıklamaları kendiniz eklemeniz gerekir. Özniteliğini eklediğinizde, derleyicinin statik analizi, sınanan değişkenin null olarak işaretli olduğunu bilir.
Bu öznitelikler için başka bir kullanım de modeldir Try* . Ve bağımsız değişkenleri için Sonkoşulları, ref out dönüş değeri üzerinden iletilir. Daha önce gösterilen (null yapılabilir devre dışı bir bağlamda) bu yöntemi göz önünde bulundurun:
bool TryGetMessage(string key, out string message)
{
if (_messageMap.ContainsKey(key))
message = _messageMap[key];
else
message = null;
return message != null;
}
Yukarıdaki yöntem tipik bir .NET deyimidir OM: dönüş değeri, message bulunan değer olarak ayarlanmış olup olmadığını veya hiçbir ileti bulunamazsa varsayılan değere ayarlandığını gösterir. Yöntemi döndürürse true , değeri message null değildir; Aksi takdirde, yöntemi message null olarak ayarlanır.
Null yapılabilir etkin bir bağlamda, bu deyimden özniteliği kullanarak iletişim kurabilirsiniz NotNullWhen . Null yapılabilir başvuru türleri için parametreler not eklediğinizde, message bir string? öznitelik oluşturun ve ekleyin:
bool TryGetMessage(string key, [NotNullWhen(true)] out string? message)
{
if (_messageMap.ContainsKey(key))
message = _messageMap[key];
else
message = null;
return message is not null;
}
Önceki örnekte, değeri message döndüğünde null değil olarak bilinir TryGetMessage true . Kod tabanınızda benzer yöntemlere aynı şekilde açıklama eklemek gerekir: bağımsız değişkenler eşit olabilir null ve yöntem döndürüldüğünde null değil olarak bilinir true .
Ayrıca ihtiyacınız olabilecek bir son öznitelik vardır. Bazen bir dönüş değerinin null durumu bir veya daha fazla bağımsız değişkenin null durumuna bağlıdır. Bu yöntemler, belirli bağımsız değişkenler olmadığında null olmayan bir değer döndürür null . Bu yöntemlere doğru şekilde açıklama eklemek için özniteliğini kullanırsınız NotNullIfNotNull . Aşağıdaki yöntemi göz önünde bulundurun:
string GetTopLevelDomainFromFullUrl(string url)
urlBağımsız değişken null değilse, çıktı değildir null . Null yapılabilir başvurular etkinleştirildikten sonra, API 'niz null bir bağımsız değişkeni kabul edebiliyorsanız daha fazla ek açıklama eklemeniz gerekir. Aşağıdaki kodda gösterildiği gibi, dönüş türüne not ekleyebilirsiniz:
string? GetTopLevelDomainFromFullUrl(string? url)
Bu da çalışır, ancak arayanlara çok fazla denetim uygulamak için zorlayacaktır null . Sözleşmenin dönüş değeri null yalnızca bağımsız değişken olduğunda olacaktır url null . Bu sözleşmeyi ifade etmek için, aşağıdaki kodda gösterildiği gibi bu yönteme açıklama ekleyebilirsiniz:
[return: NotNullIfNotNull("url")]
string? GetTopLevelDomainFromFullUrl(string? url)
Dönüş değerine ve bağımsız değişkenine, her iki durumda da olabilecek şekilde açıklama eklenmiş ? null . Özniteliği, bağımsız değişken olmadığında dönüş değerinin null olmaması gerektiğini açıklığa kavuşturulur url null .
Şu öznitelikleri kullanarak koşullu Sonkoşulları belirtirsiniz:
- MaybeNullWhen: yöntem belirtilen değeri döndürdüğünde null yapılamayan bir bağımsız değişken null olabilir
bool. - Notnullne zaman: yöntem belirtilen değeri döndürdüğünde null yapılabilir bir bağımsız değişken null olmaz
bool. - Notnullifnotnull: belirtilen parametrenin bağımsız değişkeni null değilse, dönüş değeri null olamaz.
Yardımcı Yöntemler: MemberNotNull ve MemberNotNullWhen
Bu öznitelikler, oluşturuculardan yardımcı yöntemlere ortak kod yeniden düzenlenmiş sahip olduğunuzda amacınızı belirler. C# derleyicisi, her bir Oluşturucu döndürülmeden önce null yapılamayan tüm başvuru alanlarının başlatıldığından emin olmak için oluşturucuları ve alan başlatıcıları analiz eder. Ancak, C# derleyicisi tüm yardımcı yöntemler aracılığıyla alan atamalarını izlemez. Derleyici, CS8618 alanlar doğrudan oluşturucuda başlatılmadığında, ancak bir yardımcı yönteminde değil, uyarı verir. MemberNotNullAttributeYöntemini bir yöntem bildirimine eklersiniz ve yöntemdeki null olmayan bir değere başlatılan alanları belirtirsiniz. Örneğin, aşağıdaki örneği göz önünde bulundurun:
public class Container
{
private string _uniqueIdentifier; // must be initialized.
private string? _optionalMessage;
public Container()
{
Helper();
}
public Container(string message)
{
Helper();
_optionalMessage = message;
}
[MemberNotNull(nameof(_uniqueIdentifier))]
private void Helper()
{
_uniqueIdentifier = DateTime.Now.Ticks.ToString();
}
}
Öznitelik oluşturucusunda bağımsız değişken olarak birden çok alan adı belirtebilirsiniz MemberNotNull .
, MemberNotNullWhenAttribute Bir bool bağımsız değişkenine sahiptir. MemberNotNullWhenYardımcı yönteminizin, bool Yardım yönteminizin alanları başlattığını belirten bir durum olduğu durumlarda kullanırsınız.
Yöntem oluşturduğunda null yapılabilir analizini durdur
Bazı yöntemler, genellikle özel durum yardımcıları veya diğer yardımcı yöntemler, her zaman bir özel durum oluşturarak çıkış yapılır. Ya da bir yardımcı, Boole bağımsız değişkeninin değerine göre bir özel durum oluşturabilir.
İlk durumda, DoesNotReturnAttribute metot bildirimine özniteliğini ekleyebilirsiniz. Derleyicinin null-durum analizi, ile açıklanmış bir metoda yapılan çağrıyı izleyen bir yöntemde hiçbir kodu denetlemez DoesNotReturn . Şu yöntemi göz önünde bulundurun:
[DoesNotReturn]
private void FailFast()
{
throw new InvalidOperationException();
}
public void SetState(object containedField)
{
if (containedField is null)
{
FailFast();
}
// containedField can't be null:
_field = containedField;
}
Derleyici çağrısından sonra herhangi bir uyarı vermez FailFast .
İkinci durumda, System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttribute özniteliğini yönteminin bir Boolean parametresine eklersiniz. Önceki örneği aşağıdaki gibi değiştirebilirsiniz:
private void FailFastIf([DoesNotReturnIf(true)] bool isNull)
{
if (isNull)
{
throw new InvalidOperationException();
}
}
public void SetFieldState(object? containedField)
{
FailFastIf(containedField == null);
// No warning: containedField can't be null here:
_field = containedField;
}
Bağımsız değişkenin değeri oluşturucunun değeriyle eşleştiğinde DoesNotReturnIf , derleyici bu yöntemden sonra hiçbir null durum Analizi gerçekleştirmez.
Özet
Önemli
Resmi belgelerde en son C# sürümü izlenir. Şu anda C# 9,0 için yazıyor. Kullanmakta olduğunuz C# sürümüne bağlı olarak çeşitli özellikler kullanılamayabilir. Projeniz için varsayılan C# sürümü, hedef Framework 'ü temel alır. Daha fazla bilgi için bkz. C# dil sürümü oluşturma Varsayılanları.
Null yapılabilir başvuru türleri eklemek, olabilecek değişkenlere yönelik API beklentilerinizi tanımlayan bir başlangıç sözlüğü sağlar null . Öznitelikleri, değişkenlerin, ön koşullar ve Postconditions olarak null durumunu açıklamaya yönelik daha zengin bir sözlük sağlar. Bu öznitelikler beklentilerinizi daha net bir şekilde anlatır ve API 'lerinizi kullanan geliştiriciler için daha iyi bir deneyim sağlar.
Bir null yapılabilir bağlam için kitaplıkları güncelleştirdiğinizde, API 'lerinizi kullanıcılarına doğru kullanım için bu öznitelikleri ekleyin. Bu öznitelikler, bağımsız değişkenlerin ve dönüş değerlerinin Null durumunu tam olarak açıklamanıza yardımcı olur.
- AllowNull: null yapılamayan bir alan, parametre veya özellik null olabilir.
- Disallownull: null olabilen bir alan, parametre veya özellik asla null olmamalıdır.
- MaybeNull: null yapılamayan bir alan, parametre, özellik veya dönüş değeri null olabilir.
- NotNull: null olabilen bir alan, parametre, özellik veya dönüş değeri hiçbir şekilde null olmaz.
- MaybeNullWhen: yöntem belirtilen değeri döndürdüğünde null yapılamayan bir bağımsız değişken null olabilir
bool. - Notnullne zaman: yöntem belirtilen değeri döndürdüğünde null yapılabilir bir bağımsız değişken null olmaz
bool. - Notnullifnotnull: belirtilen parametrenin bağımsız değişkeni null değilse bir parametre, özellik veya dönüş değeri null olamaz.
- Yok: bir yöntem veya özellik hiçbir şekilde döndürmez. Diğer bir deyişle, her zaman bir özel durum oluşturur.
- Yok : ilişkili
boolparametre belirtilen değere sahipse, bu yöntem veya özellik hiçbir şekilde döndürmez.