วิธีปฏิบัติที่ดีที่สุดสำหรับการใช้ประเภทข้อมูลอ้างอิงที่เป็นโมฆะสำหรับ DTO


20

ฉันมี DTO ซึ่งบรรจุด้วยการอ่านจากตาราง DynamoDB พูดว่าตอนนี้ดูเหมือนว่านี้:

public class Item
{
    public string Id { get; set; } // PK so technically cannot be null
    public string Name { get; set; } // validation to prevent nulls but this doesn't stop database hacks
    public string Description { get; set; } // can be null
}

มีวิธีปฏิบัติที่ดีที่สุดในการพัฒนาเพื่อจัดการกับสิ่งนี้หรือไม่? ฉันควรหลีกเลี่ยงตัวสร้างที่ไม่มีพารามิเตอร์เนื่องจากเล่นได้ไม่ดีกับ ORM ใน Dynamo SDK (รวมถึงอื่น ๆ )

ดูเหมือนว่าแปลกสำหรับฉันที่จะเขียนpublic string Id { get; set; } = "";เพราะสิ่งนี้จะไม่เกิดขึ้นตั้งแต่Idเป็น PK และไม่มีวันเป็นโมฆะ การใช้งานจะ""เป็นอะไรแม้ว่ามันจะทำยังไงก็ตาม

ดังนั้นวิธีปฏิบัติที่ดีที่สุดในเรื่องนี้?

  • ฉันควรจะทำเครื่องหมายพวกเขาทั้งหมดstring?ว่าพวกเขาเป็นโมฆะแม้ว่าบางคนไม่ควร
  • ฉันควรเริ่มต้นIdและNameด้วย""เพราะไม่ควรเป็นโมฆะและสิ่งนี้แสดงให้เห็นถึงเจตนาแม้ว่า""จะไม่เคยใช้
  • การรวมกันของบางอย่างข้างต้น

โปรดทราบ: นี่เป็นเรื่องเกี่ยวกับ C # 8 ประเภทอ้างอิง nullableหากคุณไม่ทราบว่าสิ่งที่พวกเขาจะไม่ตอบ


มันสกปรกเล็กน้อย แต่คุณสามารถตบ#pragma warning disable CS8618ที่ด้านบนของไฟล์
ยี่สิบ

7
แทนที่จะ= ""คุณสามารถใช้= null!ในการเริ่มต้นคุณสมบัติที่คุณรู้ว่าจะไม่ได้อย่างมีประสิทธิภาพเป็นnull(เมื่อคอมไพเลอร์มีทางรู้เลยว่า) หากDescriptionถูกต้องตามกฎหมายสามารถก็ควรจะประกาศให้เป็นnull string?อีกทางเลือกหนึ่งถ้าการตรวจสอบความไม่ถูกต้องสำหรับ DTO นั้นเป็นสิ่งที่น่ารำคาญมากกว่าความช่วยเหลือคุณสามารถห่อประเภทใน#nullable disable/ #nullable restoreเพื่อปิด NRT สำหรับประเภทนี้เท่านั้น
Jeroen Mostert

@JeroenMostert คุณควรระบุว่าเป็นคำตอบ
แมกนัส

3
@ Magnus: ฉันลังเลที่จะตอบคำถามที่ถามถึง "แนวทางปฏิบัติที่ดีที่สุด"; สิ่งต่าง ๆ นั้นกว้างและเป็นส่วนตัว ฉันหวังว่า OP สามารถใช้ความคิดเห็นของฉันเพื่อพัฒนา "แนวปฏิบัติที่ดีที่สุด" ของตนเอง
Jeroen Mostert

1
@ IvanGarcíaTopete: ในขณะที่ฉันยอมรับว่าการใช้สตริงสำหรับคีย์หลักนั้นผิดปกติและอาจไม่เหมาะสมขึ้นอยู่กับสถานการณ์การเลือกประเภทข้อมูลของ OP นั้นค่อนข้างไม่เกี่ยวข้องกับคำถาม สิ่งนี้สามารถนำไปใช้กับคุณสมบัติสตริงที่ต้องการไม่เป็นโมฆะได้ซึ่งไม่ใช่คีย์หลักหรือแม้แต่ฟิลด์สตริงที่เป็นส่วนหนึ่งของคีย์หลักแบบคอมโพสิตและคำถามจะยังคงอยู่
Jeremy Caney

คำตอบ:


12

เป็นตัวเลือกคุณสามารถใช้defaultตัวอักษรร่วมกับnull forgiving operator

public class Item
{
    public string Id { get; set; } = default!;
    public string Name { get; set; } = default!;
    public string Description { get; set; } = default!;
}

เนื่องจาก DTO ของคุณมีประชากรจาก DynamoDB คุณสามารถใช้MaybeNull/NotNull คุณสมบัติ postconditionเพื่อควบคุมความสามารถในการลบล้าง

  • MaybeNull ค่าส่งคืนที่ไม่เป็นโมฆะอาจเป็นโมฆะ
  • NotNull ค่าส่งคืน nullable จะไม่เป็นโมฆะ

แต่คุณลักษณะเหล่านี้มีผลต่อการวิเคราะห์ที่ไม่สามารถใช้ได้สำหรับผู้โทรของสมาชิกที่มีหมายเหตุประกอบอยู่ โดยทั่วไปแล้วคุณจะใช้คุณลักษณะเหล่านี้กับวิธีการส่งคืนคุณสมบัติและตัวสร้างดัชนี

ดังนั้นคุณสามารถพิจารณาคุณสมบัติทั้งหมดของคุณที่ไม่เป็นโมฆะและตกแต่งด้วยแอMaybeNullททริบิวต์เพื่อระบุว่าพวกเขาส่งคืนnullค่าที่เป็นไปได้

public class Item
{
    public string Id { get; set; } = "";
    [MaybeNull] public string Name { get; set; } = default!;
    [MaybeNull] public string Description { get; set; } = default!;
}

ตัวอย่างต่อไปนี้แสดงการใช้งานItemคลาสที่อัพเดต อย่างที่คุณเห็นบรรทัดที่สองไม่แสดงคำเตือน แต่อย่างที่สามคือ

var item = new Item();
string id = item.Id;
string name = item.Name; //warning CS8600: Converting null literal or possible null value to non-nullable type.

หรือคุณสามารถทำให้คุณสมบัติทั้งหมดเป็นโมฆะและใช้NoNullเพื่อระบุว่าค่าส่งคืนไม่สามารถnull( Idตัวอย่าง)

public class Item
{
    [NotNull] public string? Id { get; set; }
    public string? Name { get; set; }
    public string? Description { get; set; }
}

คำเตือนจะเหมือนกันกับตัวอย่างก่อนหน้านี้

นอกจากนี้ยังมีแอAllowNull/DisallowNull ททริบิวต์เงื่อนไขเบื้องต้นสำหรับพารามิเตอร์อินพุตคุณสมบัติและตัวเซ็ตดัชนีซึ่งทำงานในลักษณะเดียวกัน

  • AllowNull อาร์กิวเมนต์อินพุตที่ไม่เป็นโมฆะอาจเป็นโมฆะ
  • DisallowNull อาร์กิวเมนต์อินพุตที่ nullable ไม่ควรเป็น null

ฉันไม่คิดว่ามันจะช่วยคุณได้เนื่องจากชั้นเรียนของคุณมีประชากรจากฐานข้อมูล แต่คุณสามารถใช้พวกเขาเพื่อควบคุมความไม่แน่นอนของตัวตั้งค่าคุณสมบัติเช่นนี้สำหรับตัวเลือกแรก

[MaybeNull, AllowNull] public string Description { get; set; }

และสำหรับคนที่สอง

[NotNull, DisallowNull] public string? Id { get; set; }

รายละเอียดที่เป็นประโยชน์และตัวอย่างของการโพสต์ / เงื่อนไขเบื้องต้นสามารถพบได้ในบทความ devblog นี้


6

คำตอบของตำราเรียนในสถานการณ์นี้คือใช้string?สำหรับIdคุณสมบัติของคุณแต่ยังตกแต่งด้วย[NotNull]คุณสมบัติ:

public class Item
{
  [NotNull] public string? Id { get; set; }
  public string Name { get; set; }
  public string? Description { get; set; }
}

อ้างอิง:ตามเอกสารที่[NotNull]แอตทริบิวต์ "ระบุว่าการส่งออกไม่ได้เป็นโมฆะแม้ว่าจะเป็นชนิดที่สอดคล้องกันช่วยให้มัน."

แล้วเกิดอะไรขึ้นตรงนี้ล่ะ?

  1. ครั้งแรกที่string?พิมพ์กลับช่วยป้องกันการเรียบเรียงจากคำเตือนคุณว่าทรัพย์สินที่จะเตรียมในระหว่างการก่อสร้างจึงจะเริ่มต้นnullที่จะ
  2. จากนั้น[NotNull]แอ็ตทริบิวต์จะป้องกันการเตือนเมื่อกำหนดคุณสมบัติให้กับตัวแปรที่ไม่เป็นโมฆะหรือพยายามปฏิเสธเนื่องจากคุณแจ้งการวิเคราะห์การไหลของสแตติกของคอมไพเลอร์ซึ่งในทางปฏิบัติแล้วคุณสมบัตินี้จะไม่มีทางเป็นnullไปได้

คำเตือน:เช่นเดียวกับทุกกรณีที่เกี่ยวข้องกับบริบทความเป็นโมฆะของ C # ไม่มีทางเทคนิคใดที่จะหยุดคุณไม่ให้คืนnullค่าที่นี่และอาจแนะนำข้อยกเว้นดาวน์สตรีม เช่นไม่มีการตรวจสอบความถูกต้องแบบรันไทม์นอกกรอบ C # ที่เคยมีให้ทั้งหมดคือคำเตือนของคอมไพเลอร์ เมื่อคุณแนะนำ[NotNull]คุณจะมีประสิทธิภาพเหนือคำเตือนนั้นโดยให้คำแนะนำเกี่ยวกับตรรกะทางธุรกิจของคุณ เช่นนี้เมื่อคุณใส่คำอธิบายคุณสมบัติด้วย[NotNull]คุณจะต้องรับผิดชอบต่อความมุ่งมั่นของคุณว่า "สิ่งนี้จะไม่เกิดขึ้นเนื่องจากIdเป็น PK และไม่มีวันเป็นโมฆะ"

เพื่อช่วยให้คุณรักษาความมุ่งมั่นนั้นคุณอาจต้องการเพิ่มคำอธิบายประกอบคุณสมบัติด้วย[DisallowNull]แอตทริบิวต์:

public class Item
{
  [NotNull, DisallowNull] public string? Id { get; set; }
  public string Name { get; set; }
  public string? Description { get; set; }
}

อ้างอิง:ตามเอกสารที่[DisallowNull]แอตทริบิวต์ "ระบุว่าnullไม่ได้รับอนุญาตเป็น input แม้ว่าจะเป็นชนิดที่สอดคล้องกันช่วยให้มัน."

สิ่งนี้อาจไม่เกี่ยวข้องในกรณีของคุณเนื่องจากมีการกำหนดค่าผ่านทางฐานข้อมูล แต่แอ[DisallowNull]ททริบิวจะให้คำเตือนหากคุณพยายามกำหนดค่าnull(สามารถ) ให้กับIdคุณแม้ว่าประเภทการส่งคืนจะเป็นแบบนั้นก็ตาม โมฆะ ในเรื่องที่Idจะทำหน้าที่ตรงเหมือนstringเท่าที่วิเคราะห์การไหลของ C # 's คงเป็นห่วงในขณะที่ยังช่วยให้ค่าที่จะยังคงเตรียมระหว่างการก่อสร้างของวัตถุและจำนวนประชากรของสถานที่ให้บริการ

หมายเหตุ:ในขณะที่คนอื่น ๆ ได้กล่าวถึงคุณยังสามารถบรรลุผลที่เหมือนจริงโดยการกำหนดIdค่าเริ่มต้นของทั้งสองหรือdefault! นี่คือยอมรับว่าค่อนข้างชอบโวหาร ฉันต้องการใช้คำอธิบายประกอบที่เป็นโมฆะเนื่องจากมีความชัดเจนมากขึ้นและให้การควบคุมที่ละเอียดในขณะที่มันเป็นการง่ายที่จะใช้วิธีปิดคอมไพเลอร์ การกำหนดค่าเริ่มต้นให้กับคุณสมบัติอย่างชัดเจนด้วยค่านั้นก็ทำให้ฉันรำคาญถ้าฉันรู้ว่าฉันจะไม่ใช้ค่านั้น - แม้ว่าจะเป็นค่าเริ่มต้นก็ตามnull!!


-2

สตริงเป็นประเภทการอ้างอิงและเป็นโมฆะเสมอคุณไม่จำเป็นต้องทำอะไรเป็นพิเศษ คุณอาจมีปัญหาในภายหลังเฉพาะในกรณีที่คุณต้องการแมปวัตถุชนิดนี้กับอีกวัตถุหนึ่ง แต่คุณสามารถจัดการกับสิ่งนั้นได้ในภายหลัง


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.