หน้าแกลเลอรี่ Resharper
ประวัติความเป็นมาของการเปลี่ยนแปลง
แนวคิดพื้นฐานของส่วนขยายนี้คือการเปลี่ยนพฤติกรรมของการวิเคราะห์ความไม่แน่นอนแบบคงที่ของ Resharper เพื่อให้องค์ประกอบรหัสเฉพาะได้รับคำอธิบายประกอบที่เป็นค่าเริ่มต้นโดยไม่ต้องระบุแอตทริบิวต์ [NotNull] หรือ [CanBeNull] ที่ชัดเจน ตัวอย่างเช่นประเภทการอ้างอิงในพารามิเตอร์เมธอดนั้นเป็นค่าเริ่มต้น [NotNull] (→พวกเขาต้องการ [CanBeNull] ที่ชัดเจนเพื่อให้กลายเป็นโมฆะ)

ด้วยการเปิด ใช้งานความไม่แน่นอนโดย ปริยายสำหรับองค์ประกอบไวยากรณ์ที่กำหนดค่าได้และกำหนดได้กฎต่อไปนี้จะใช้
[NotNull][CanBeNull] ที่ชัดเจนnull นั้นโดยปริยาย [CanBeNull]สรุปรหัสแสดงในภาพด้านบน ...
public string Bar ( string a , [ CanBeNull ] string b , string c = null )
{
// ...
}... โดยปริยายกลายเป็น ...
[ NotNull ]
public string Bar ( [ NotNull ] string a , [ CanBeNull ] string b , [ CanBeNull ] string c = null )
{
// ...
}[NotNull] เป็นค่าเริ่มต้น หากไม่มีส่วนขยายนี้ค่าความสามารถในการเป็นค่าเริ่มต้นคือ "ไม่ทราบ" ซึ่งหมายความว่า Resharper จะไม่รวมองค์ประกอบเหล่านี้สำหรับการวิเคราะห์ความไม่แน่นอน อันเป็นผลมาจากการเปลี่ยนแปลงค่าเริ่มต้นของส่วนขยายนี้เราต้องวางคำอธิบายประกอบ [CanBeNull] เฉพาะสำหรับองค์ประกอบรหัส เฉพาะ (เช่นพารามิเตอร์ประเภทอ้างอิงที่ควรได้รับอนุญาตให้ส่งผ่าน null เป็นอาร์กิวเมนต์) และไม่จำเป็นต้องมีคำอธิบายประกอบที่ null สำหรับกรณีส่วนใหญ่
Resharper 9.2 แนะนำการสนับสนุนสำหรับการวิเคราะห์ความสามารถในการเป็นโมฆะสำหรับวิธีการ async ( Task<T> การพิมพ์กลับ) ด้วยการเปิดใช้ งานความไม่แน่นอนโดยนัย สำหรับค่าการส่งคืนวิธี Task<T> วิธีการพิมพ์กลับยังกลายเป็นโดยปริยาย [ItemNotNull] (Resharper ใช้แอตทริบิวต์นี้เพื่ออ้างถึง ค่า ของ Task<T> ) สำหรับ Task<T> ค่าส่งคืนสิ่งนี้สามารถแทนที่ด้วย [ItemCanBeNull]
โปรแกรมตัวอย่างต่อไปนี้มี NullReferenceException ที่อาจเกิดขึ้นใน command.Equals("Hello") เพราะโปรแกรมเมอร์พลาดที่ GetCommand() สามารถคืนค่า null ได้เช่นกัน
public static void Main ( string [ ] args )
{
string command = GetCommand ( args ) ;
if ( command . Equals ( "Hello" ) )
Console . WriteLine ( "Hello World!" ) ;
}
private static string GetCommand ( string [ ] args )
{
if ( args . Length < 1 )
return null ;
return args [ 0 ] ;
}ด้วยการเปิดใช้ งานความไม่แน่นอนโดยนัย ข้อผิดพลาดนี้จะถูกตรวจพบโดยการวิเคราะห์แบบคงที่ของ Resharper
null ใน GetCommand() เพราะวิธีนี้จะมีคำอธิบายประกอบโดยปริยายว่า [NotNull][CanBeNull] เพื่อ GetCommand()[CanBeNull] , Resharper ตอนนี้จะเตือนเกี่ยวกับ NullReferenceException ที่อาจเกิดขึ้นใน command.Equals("Hello") การโทรใน Main() ในตัวอย่างด้านบน ความไม่แน่นอนโดย นัยบังคับให้โปรแกรมเมอร์แก้ไขแอตทริบิวต์ [CanBeNull] ที่หายไปบน GetCommand() สิ่งนี้แสดงให้เห็นว่าจำนวนคำอธิบายประกอบ [CanBeNull] จะเพิ่มขึ้นในฐานรหัสและดังนั้นจึงไม่เพียง แต่ปรับปรุงการวิเคราะห์แบบคงที่ของ Resharper แต่ยังรวมถึงเอกสารของลายเซ็นวิธี (สัญญา)
เป้าหมายอีกประการหนึ่งของการขยายนี้คือการนำการวิเคราะห์แบบคงที่ของ Resharper เข้าด้วยกันกับการตรวจสอบโมฆะโดยนัยของ Fody Nullguard ตัวอย่างเช่น Weaver Fody นี้จะ throw new ArgumentNullException(/*...*/) สำหรับพารามิเตอร์วิธีการลงในวิธีการโดยใช้กฎเดียวกันกับ ความเป็นโมฆะโดยนัย กล่าวอีกนัยหนึ่งผู้ประกอบนี้เพิ่ม การตรวจสอบรันไทม์ เพื่อการวิเคราะห์ แบบคงที่ ของ Resharper
C# 8 จะได้รับ ประเภทการอ้างอิงที่เป็นโมฆะ ซึ่งนำประเภทตัวเลือกลงในภาษา C# สิ่งนี้ตรงกับความหมายของ ความเป็นโมฆะโดยนัย และไปให้ไกลยิ่งขึ้นเพราะมันขยายไปยังคนในท้องถิ่นพารามิเตอร์ทั่วไป ... เพราะคำอธิบายประกอบที่เป็นโมฆะทำงานในระดับประเภท
[ CanBeNull ]
string Bar ( [ CanBeNull ] string a , string b )
{
string result = a ;
return result ;
}... แล้วสอดคล้องกับ ...
string ? Bar ( string ? a , string b )
{
string ? result = a ;
return result ;
} สิ่งนี้จะทำให้ ความไม่แน่นอนโดยนัย ไม่จำเป็นในอนาคตและในขณะเดียวกันเส้นทาง "อัพเกรด" ที่สมบูรณ์แบบเพราะฐานรหัสที่ดี [CanBeNull] ที่ดีจะสามารถพกพาได้อย่างง่ายดายไปยัง C# 8
ตั้งแต่เวอร์ชัน 2016.1 Resharper รองรับ (ใน "โหมดภายใน") คุณสมบัติที่เปรียบเทียบได้ (ดู การตรวจสอบรหัส | การตั้งค่า ) ที่มีความแตกต่างต่อไปนี้
ความไม่พอใจโดยนัย ...
[NotNull] องค์ประกอบองค์ประกอบที่ชัดเจนหรือโดยปริยาย [NotNull] จะถูกเน้นด้วยขีดเส้นใต้ประ (ดูที่สีชมพูขีดเส้นใต้ใน Bar -วิธีการในภาพหน้าจอตัวอย่างด้านบน) สิ่งนี้ช่วยในการรับรู้องค์ประกอบ [NotNull] ทั้งหมดโดยเฉพาะอย่างยิ่งการอนุมานองค์ประกอบ [NotNull] จากคลาสพื้นฐานและองค์ประกอบรหัสซึ่งกำหนดค่าเป็น [NotNull] โดยปริยาย
การไฮไลต์สามารถเปิดใช้งาน/ปิดใช้งานได้ในหน้าตัวเลือก ความไม่แน่นอนโดยนัย และสามารถกำหนดค่าสีในตัวเลือก "ฟอนต์และสี" ของ Visual Studio
ความไม่แน่นอนโดยนัยสามารถเปิดใช้งานหรือปิดใช้งานสำหรับองค์ประกอบไวยากรณ์เฉพาะใน การตรวจสอบรหัส | หน้าตัวเลือก ความไม่แน่นอนโดยนัย

ความไม่แน่นอนโดยปริยาย สามารถกำหนดค่าได้ด้วยรหัสโดยใช้แอ AssemblyMetadataAttribute สิ่งนี้มีข้อได้เปรียบที่การกำหนดค่าได้รับการรวบรวมลงในแอสเซมบลีเพื่อให้ผู้บริโภคของแอ สเซมบลีพร้อมกับการติดตั้งโดยนัย ที่ติดตั้งได้รับคำอธิบายประกอบที่เป็นโมฆะโดยนัยเดียวกันขององค์ประกอบโค้ดที่รวบรวมไว้ ภายใน โซลูชันของห้องสมุด
ตัวอย่าง:
[ assembly : AssemblyMetadata ( "ImplicitNullability.AppliesTo" ,
"InputParameters, RefParameters, OutParametersAndResult, Fields, Properties" ) ]
[ assembly : AssemblyMetadata ( "ImplicitNullability.Fields" , "RestrictToReadonly" ) ]
[ assembly : AssemblyMetadata ( "ImplicitNullability.Properties" , "RestrictToGetterOnly" ) ]
[ assembly : AssemblyMetadata ( "ImplicitNullability.GeneratedCode" , "Exclude" ) ]นอกเหนือจากการเปลี่ยนแปลงพฤติกรรมของการวิเคราะห์ความไม่แน่นอนแล้วคำเตือนการตรวจสอบรหัสต่อไปนี้มีให้โดยส่วนขยายนี้
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับคำเตือนเหล่านี้ (และแรงจูงใจของพวกเขา) ดูคำอธิบายของพวกเขาใน การตรวจสอบรหัส Resharper | หน้าตัวเลือก ความรุนแรงการตรวจสอบ
ID: ImplicitNotNullConflictInHierarchy
abstract class Base
{
public abstract void Method ( [ CanBeNull ] string a ) ;
}
class Derived : Base
{
// "Implicit NotNull conflicts with nullability in base type":
public override void Method ( string a )
{
}
} ID: ImplicitNotNullElementCannotOverrideCanBeNull
abstract class Base
{
[ CanBeNull ]
public abstract string Method ( ) ;
}
class Derived : Base
{
// "Implicit NotNull element cannot override CanBeNull in base type, nullability should be explicit":
public override string Method ( ) => "" ;
} IDS: ImplicitNotNullOverridesUnknownBaseMemberNullability resp ImplicitNotNullResultOverridesUnknownBaseMemberNullability
class Derived : External . Class /* (external code with unannotated 'Method' and 'Function') */
{
// "Implicit NotNull overrides unknown nullability of base member, nullability should be explicit":
public override void Method ( string a )
{
}
// "Implicit NotNull result or out parameter overrides unknown nullability of base member,
// nullability should be explicit":
public override string Function ( ) => "" ;
} ID: NotNullOnImplicitCanBeNull
// "Implicit CanBeNull element has an explicit NotNull annotation":
void Foo ( [ NotNull ] int ? a )
{
} ขอบคุณมากสำหรับ Fabian Schmied ที่สนับสนุนการออกแบบและความคิดของ ความไม่แน่นอนโดยนัย