วิธีที่ไม่ซ้ำในการใช้ตัวดำเนินการ Null Coalescing [ปิด]


165

ฉันรู้วิธีมาตรฐานในการใช้ตัวดำเนินการรวม Null ใน C # คือการตั้งค่าเริ่มต้น

string nobody = null;
string somebody = "Bob Saget";
string anybody = "";

anybody = nobody   ?? "Mr. T"; // returns Mr. T
anybody = somebody ?? "Mr. T"; // returns "Bob Saget"

แต่มีอะไรอีกบ้างที่สามารถ??ใช้เพื่อ? ดูเหมือนว่าจะไม่มีประโยชน์เท่าโอเปอร์เรเตอร์ที่ประกอบไปด้วยนอกจากจะกระชับและอ่านง่ายกว่า:

nobody = null;
anybody = nobody == null ? "Bob Saget" : nobody; // returns Bob Saget

เนื่องจากน้อยกว่าที่รู้เกี่ยวกับตัวดำเนินการรวมศูนย์ว่าง ...

  • คุณเคยใช้??อย่างอื่นใช่ไหม

  • เป็น??สิ่งที่จำเป็นหรือคุณก็ควรจะใช้ประกอบ ternary (ว่าส่วนใหญ่มีความคุ้นเคยกับ)

คำตอบ:


216

ก่อนอื่นเลยมันง่ายกว่าการเชื่อมโยงแบบมาตรฐานทั่วไป:

string anybody = parm1 ?? localDefault ?? globalDefault;

เมื่อเทียบกับ

string anyboby = (parm1 != null) ? parm1 
               : ((localDefault != null) ? localDefault 
               : globalDefault);

นอกจากนี้ยังทำงานได้ดีถ้าวัตถุที่เป็นไปได้ null ไม่ได้เป็นตัวแปร:

string anybody = Parameters["Name"] 
              ?? Settings["Name"] 
              ?? GlobalSetting["Name"];

เมื่อเทียบกับ

string anybody = (Parameters["Name"] != null ? Parameters["Name"] 
                 : (Settings["Name"] != null) ? Settings["Name"]
                 :  GlobalSetting["Name"];

12
ผูกมัดเป็นบวกใหญ่สำหรับผู้ประกอบการเอาพวงของการด้อยซ้ำซ้อน
ชาคริต

1
ฉันเพิ่งใช้มันในวันนี้เพื่อแทนที่บล็อก IF ง่ายๆที่ฉันเขียนก่อนที่ฉันจะรู้เกี่ยวกับตัวดำเนินการรวมตัวที่สามหรือเป็นโมฆะ กิ่งก้านที่แท้จริงและเท็จของคำสั่ง IF ดั้งเดิมเรียกว่าวิธีการเดียวกันแทนที่หนึ่งในอาร์กิวเมนต์ด้วยค่าที่ต่างกันหากอินพุตที่แน่นอนเป็น NULL ด้วยโอเปอเรเตอร์ null ที่รวมกันจะเป็นการโทรเพียงครั้งเดียว นี่เป็นวิธีที่มีประสิทธิภาพจริงๆเมื่อคุณมีวิธีที่ต้องการการทดแทนสองอย่างหรือมากกว่านั้น!
David A. Gray

177

ฉันเคยใช้เป็นสายการบินหนึ่งซับขี้เกียจ:

public MyClass LazyProp
{
    get { return lazyField ?? (lazyField = new MyClass()); }
}

สามารถอ่านได้? ตัดสินใจด้วยตัวเอง


6
อืมคุณพบตัวอย่างที่ "ทำไมคนที่ต้องการใช้มันเป็น IF ที่ทำให้งงงวย" ... ที่จริงแล้วฉันสามารถอ่านได้
Godeke

6
ฉันอาจจะหายไปบางสิ่งบางอย่าง (ส่วนใหญ่ฉันใช้ Java) แต่ไม่มีสภาพการแข่งขันที่นั่น?
Justin K

9
@Justin K - มีเพียงเงื่อนไขการแข่งขันหากมีหลายเธรดที่เข้าถึงคุณสมบัติ LazyProp ของวัตถุเดียวกัน มันสามารถแก้ไขได้อย่างง่ายดายด้วยการล็อคถ้าต้องการความปลอดภัยของเธรดของแต่ละอินสแตนซ์ ชัดเจนในตัวอย่างนี้ไม่จำเป็น
Jeffrey L Whitledge

5
@ Jeffrey: ถ้ามันชัดเจนฉันจะไม่ถามคำถาม :) เมื่อฉันเห็นตัวอย่างนั้นฉันก็นึกถึงสมาชิกซิงเกิลทันทีและเนื่องจากฉันได้ทำการเข้ารหัสส่วนใหญ่ในสภาพแวดล้อมแบบมัลติเธรด ... แต่ถ้าคุณคิดว่ารหัสถูกต้อง
Justin K

7
ไม่จำเป็นต้องเป็น Singleton ที่จะมีสภาพการแข่งขัน เพียงอินสแตนซ์ที่แชร์ของคลาสที่มี LazyProp และหลายเธรดที่เข้าถึง LazyProp Lazy <T> เป็นวิธีที่ดีกว่าในการทำสิ่งนี้และเป็น threadsafe โดยค่าเริ่มต้น (คุณสามารถเลือกที่จะแก้ไขความปลอดภัยของ Lazy <T>)
Niall Connaughton

52

ฉันพบว่ามีประโยชน์ในสองวิธี "แปลกเล็กน้อย":

  • เป็นทางเลือกสำหรับการมีoutพารามิเตอร์เมื่อเขียนรูทีนTryParse(เช่นส่งคืนค่า null หากการแยกวิเคราะห์ล้มเหลว)
  • ในฐานะตัวแทน "ไม่รู้" สำหรับการเปรียบเทียบ

หลังต้องการข้อมูลเพิ่มเติมเล็กน้อย โดยทั่วไปเมื่อคุณสร้างการเปรียบเทียบกับองค์ประกอบหลายรายการคุณต้องดูว่าส่วนแรกของการเปรียบเทียบ (เช่นอายุ) ให้คำตอบที่ชัดเจนจากนั้นส่วนถัดไป (เช่นชื่อ) เฉพาะในกรณีที่ส่วนแรกไม่ได้ช่วย การใช้ตัวดำเนินการรวมศูนย์ว่างหมายความว่าคุณสามารถเขียนการเปรียบเทียบที่ค่อนข้างง่าย (ไม่ว่าจะเป็นการสั่งซื้อหรือความเท่าเทียมกัน) ตัวอย่างเช่นการใช้คลาสตัวช่วยสองตัวในMiscUtil :

public int Compare(Person p1, Person p2)
{
    return PartialComparer.Compare(p1.Age, p2.Age)
        ?? PartialComparer.Compare(p1.Name, p2.Name)
        ?? PartialComparer.Compare(p1.Salary, p2.Salary)
        ?? 0;
}

เป็นที่ยอมรับตอนนี้ฉันมี ProjectionComparer ใน MiscUtil พร้อมด้วยส่วนขยายบางอย่างซึ่งทำให้สิ่งนี้ง่ายยิ่งขึ้น - แต่ก็ยังเรียบร้อย

เดียวกันสามารถทำได้สำหรับการตรวจสอบความเท่าเทียมกันอ้างอิง (หรือเป็นโมฆะ) ที่จุดเริ่มต้นของการดำเนินการเท่ากับ


ฉันชอบสิ่งที่คุณทำกับ PartialComparer แต่กำลังมองหากรณีที่ฉันต้องการเก็บตัวแปรนิพจน์ที่ประเมินไว้ ฉันไม่มีประสบการณ์ใน lambdas และส่วนขยายดังนั้นคุณสามารถดูว่าต่อไปนี้เป็นไปตามรูปแบบที่คล้ายกัน (เช่นมันทำงาน) stackoverflow.com/questions/1234263/#1241780
maxwellb

33

ข้อดีอีกประการคือผู้ประกอบการที่ต้องใช้การประเมินสองครั้งหรือตัวแปรชั่วคราว

ลองพิจารณาสิ่งนี้เช่น:

string result = MyMethod() ?? "default value";

ขณะที่อยู่กับผู้ประกอบการที่คุณอยู่ด้วย:

string result = (MyMethod () != null ? MyMethod () : "default value");

ซึ่งเรียก MyMethod สองครั้งหรือ:

string methodResult = MyMethod ();
string result = (methodResult != null ? methodResult : "default value");

ไม่ว่าจะด้วยวิธีใดตัวดำเนินการรวมศูนย์ว่างจะสะอาดกว่าและฉันคิดว่ามีประสิทธิภาพมากกว่า


1
+1 นี่เป็นเหตุผลสำคัญอย่างหนึ่งที่ฉันชอบตัวดำเนินการรวมศูนย์ว่าง มันมีประโยชน์อย่างยิ่งเมื่อการโทรMyMethod()มีผลข้างเคียงใด ๆ
CVn

หากMyMethod()ไม่มีผลใด ๆ นอกเหนือจากการคืนค่าคอมไพเลอร์รู้ว่าไม่ควรเรียกมันสองครั้งดังนั้นคุณไม่ต้องกังวลเกี่ยวกับประสิทธิภาพที่นี่ในกรณีส่วนใหญ่
TinyTimZamboni

มันยังช่วยให้สิ่งต่าง ๆ ที่สามารถอ่านได้มากขึ้น IMHO เมื่อMyMethod()เป็นลำดับของวัตถุประ เช่น:myObject.getThing().getSecondThing().getThirdThing()
xdhmoore

@TinyTimZamboni คุณมีการอ้างอิงสำหรับพฤติกรรมของคอมไพเลอร์นี้หรือไม่?
Kuba Wyrostek

@KubaWyrostek ฉันไม่มีความรู้เกี่ยวกับการทำงานเฉพาะของ C # คอมไพเลอร์ แต่ฉันมีประสบการณ์บางอย่างเกี่ยวกับทฤษฎีคอมไพเลอร์แบบคงที่กับ llvm มีหลายวิธีที่คอมไพเลอร์สามารถใช้เพื่อเพิ่มประสิทธิภาพการโทรเช่นนี้ Global Value Numberingจะสังเกตเห็นว่าการเรียกสองครั้งMyMethodนั้นเหมือนกันในบริบทนี้โดยสมมติว่าMyMethodเป็นฟังก์ชั่น Pure ตัวเลือกอื่นคือการบันทึกอัตโนมัติหรือเพียงแค่ปิดฟังก์ชั่นแคช ในทางกลับกัน: en.wikipedia.org/wiki/Global_value_numbering
TinyTimZamboni

23

สิ่งที่ต้องพิจารณาอีกประการหนึ่งคือผู้ประกอบการรวมตัวกันไม่ได้เรียกวิธีการรับทรัพย์สินสองครั้งเช่นเดียวกับที่ประกอบไปด้วย

ดังนั้นจึงมีสถานการณ์ที่คุณไม่ควรใช้ไตรภาคเช่น:

public class A
{
    var count = 0;
    private int? _prop = null;
    public int? Prop
    {
        get 
        {
            ++count;
            return _prop
        }
        set
        {
            _prop = value;
        }
    }
}

ถ้าคุณใช้:

var a = new A();
var b = a.Prop == null ? 0 : a.Prop;

ทะเยอทะยานจะถูกเรียกสองครั้งและcountตัวแปรจะเท่ากับ 2 และถ้าคุณใช้:

var b = a.Prop ?? 0

countตัวแปรจะเท่ากับ 1 เท่าที่ควร


4
สิ่งนี้สมควรได้รับการโหวตมากขึ้น ฉันได้อ่านหลายครั้งมากเลยที่??เป็นเทียบเท่า?:การ
Kuba Wyrostek

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

15

ข้อได้เปรียบที่ใหญ่ที่สุดที่ฉันพบกับ??โอเปอเรเตอร์คือคุณสามารถแปลงประเภทของค่าที่ไม่สามารถเปลี่ยนเป็นชนิดที่ไม่เป็นโมฆะได้อย่างง่ายดาย:

int? test = null;
var result = test ?? 0; // result is int, not int?

ฉันมักใช้สิ่งนี้ในการค้นหา Linq:

Dictionary<int, int?> PurchaseQuantities;
// PurchaseQuantities populated via ASP .NET MVC form.
var totalPurchased = PurchaseQuantities.Sum(kvp => kvp.Value ?? 0);
// totalPurchased is int, not int?

ฉันอาจจะสายไปนิดที่นี่ kvp == nullแต่ที่ตัวอย่างที่สองถ้าจะโยน และจริงๆแล้วNullable<T>มีGetValueOrDefaultวิธีการที่ฉันใช้ตามปกติ
CompuChip

6
KeyValuePair เป็นประเภทค่าในกรอบงาน. NET ดังนั้นการเข้าถึงคุณสมบัติใด ๆ ของมันจะไม่ทำให้เกิดข้อยกเว้นการอ้างอิงเป็นโมฆะ msdn.microsoft.com/en-us/library/5tbh8a42(v=vs.110).aspx
Ryan

9

ฉันเคยใช้ ในการใช้งาน IDataErrorInfo ของฉัน:

public string Error
{
    get
    {
        return this["Name"] ?? this["Address"] ?? this["Phone"];
    }
}

public string this[string columnName]
{
    get { ... }
}

หากคุณสมบัติส่วนบุคคลใด ๆ อยู่ในสถานะ "ข้อผิดพลาด" ฉันได้รับข้อผิดพลาดนั้นมิฉะนั้นฉันจะได้รับ null ทำงานได้ดีจริงๆ


น่าสนใจ คุณกำลังใช้คุณสมบัติ "this" เป็นคุณสมบัติ ฉันไม่เคยทำอย่างนั้น
Armstrongest

ใช่มันเป็นส่วนหนึ่งของการทำงานของ IDataErrorInfo โดยทั่วไปไวยากรณ์นั้นมีประโยชน์เฉพาะกับคลาสคอลเล็กชัน
Matt Hamilton

4
คุณกำลังจัดเก็บข้อความผิดพลาดในthis["Name"], this["Address"]ฯลฯ ??
แอนดรู

7

คุณสามารถใช้ตัวดำเนินการรวมศูนย์ว่างเปล่าเพื่อทำให้เป็นบิตที่สะอาดกว่าเพื่อจัดการเคสที่ไม่ได้ตั้งค่าพารามิเตอร์เพิ่มเติม:

public void Method(Arg arg = null)
{
    arg = arg ?? Arg.Default;
    ...

มันจะไม่ดีถ้าบรรทัดนี้สามารถเขียนเป็นarg ?= Arg.Default?
Jesse de Wit

6

ฉันชอบที่จะใช้ตัวดำเนินการรวมศูนย์เป็นโมฆะเพื่อโหลดคุณสมบัติบางอย่าง

ตัวอย่างที่ง่ายมาก (และวางแผน) เพียงเพื่อแสดงให้เห็นถึงจุดของฉัน:

public class StackOverflow
{
    private IEnumerable<string> _definitions;
    public IEnumerable<string> Definitions
    {
        get
        {
            return _definitions ?? (
                _definitions = new List<string>
                {
                    "definition 1",
                    "definition 2",
                    "definition 3"
                }
            );
        }
    } 
}

Resharper จะแนะนำสิ่งนี้เป็น refactor สำหรับโหลดแบบ "ดั้งเดิม"
arichards

5

คือ ?? จำเป็นหรือคุณควรใช้ผู้ประกอบการที่ประกอบไปด้วย (ที่คุ้นเคยกับ)

ที่จริงแล้วประสบการณ์ของฉันคือว่ามีคนไม่กี่คนที่คุ้นเคยกับผู้ประกอบการที่สาม (หรือมากกว่านั้นอย่างถูกต้องผู้ดำเนินการตามเงื่อนไข?:คือ " ผู้ประกอบการ" ในความหมายเดียวกับที่||เป็นเลขฐานสองหรือไม่คู่หรือ+ทั้งคู่ เฉพาะผู้ประกอบการที่ประกอบไปด้วยสามภาษา) อย่างน้อยในตัวอย่างที่ จำกัด คำสั่งของคุณจะล้มเหลว

นอกจากนี้ดังที่กล่าวไว้ก่อนหน้านี้มีสถานการณ์ที่สำคัญอย่างหนึ่งเมื่อตัวดำเนินการรวมศูนย์ว่างมีประโยชน์มากและนั่นคือเมื่อใดก็ตามที่นิพจน์ที่จะประเมินมีผลข้างเคียงใด ๆ เลย ในกรณีดังกล่าวคุณไม่สามารถใช้โอเปอเรเตอร์ที่มีเงื่อนไขโดยไม่มี (a) แนะนำตัวแปรชั่วคราวหรือ (b) เปลี่ยนตรรกะจริงของแอปพลิเคชัน (b) เห็นได้ชัดว่าไม่เหมาะสมในสถานการณ์ใด ๆ และในขณะที่เป็นการตั้งค่าส่วนตัวฉันไม่ชอบที่จะทำให้ขอบเขตการประกาศมีจำนวนมากเกินขอบเขตแม้ว่าตัวแปรอายุสั้นดังนั้นตัวแปร (a) ก็เช่นกัน สถานการณ์เฉพาะ

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


แสดงความคิดเห็นช้ามากจากฉัน - แต่ยินดีที่ได้เห็นบางคนกล่าวว่าโอเปอเรเตอร์เป็นผู้ดำเนินการที่มีอาร์กิวเมนต์สามข้อ (ซึ่งตอนนี้มีมากกว่าหนึ่งใน C #)
Steve Kidd

5

สิ่งหนึ่งที่ผมได้รับการทำมากเมื่อเร็ว ๆ นี้โดยใช้ coalescing null asสำหรับการสำรองข้อมูลเพื่อ ตัวอย่างเช่น:

object boxed = 4;
int i = (boxed as int?) ?? 99;

Console.WriteLine(i); // Prints 4

นอกจากนี้ยังมีประโยชน์ในการสำรองโซ่ยาว ๆ?.ที่อาจล้มเหลวได้

int result = MyObj?.Prop?.Foo?.Val ?? 4;
string other = (MyObj?.Prop?.Foo?.Name as string)?.ToLower() ?? "not there";

4

ปัญหาเพียงอย่างเดียวคือตัวดำเนินการ null-coalesce ไม่พบสตริงว่าง


กล่าวคือ

string result1 = string.empty ?? "dead code!";

string result2 = null ?? "coalesced!";

เอาท์พุท:

result1 = ""

result2 = coalesced!

ฉันกำลังมองหาที่เอาชนะ? ผู้ประกอบการที่จะหลีกเลี่ยงปัญหานี้ มันจะเป็นประโยชน์หากมีสิ่งนี้อยู่ใน Framework

คิด?


คุณสามารถทำได้ด้วยวิธีการขยาย แต่ฉันเห็นด้วยมันจะเป็นการเพิ่มรหัสและมีประโยชน์มากในบริบทเว็บ
Armstrongest

ใช่นี่เป็นสถานการณ์ที่เกิดขึ้นบ่อยครั้ง ... แม้จะมีวิธีการพิเศษ String.IsNullOrEmpty (string) ...
Max Galkin

12
"ตัวดำเนินการ null-coalesce ตรวจไม่พบสตริงว่าง" มันเป็นตัวดำเนินการnull ที่ไม่รวมตัวดำเนินการnullOrEmpty -coalescing และโดยส่วนตัวแล้วฉันเกลียดการผสมค่าว่างและค่าว่างในภาษาที่แยกความแตกต่างระหว่างสองอย่างนี้ซึ่งทำให้การเชื่อมต่อกับสิ่งที่ไม่น่ารำคาญ และฉันก็ค่อนข้างย้ำคิดย้ำดังนั้นมันทำให้ฉันรำคาญเมื่อภาษา / การใช้งานไม่แยกความแตกต่างระหว่างทั้งสองต่อไปแม้ว่าฉันจะเข้าใจเหตุผลว่าทำไม (เช่นใน [การใช้งานส่วนใหญ่ของ?] SQL)
JAB

3
??ไม่สามารถโหลดมากเกินไป: msdn.microsoft.com/en-us/library/8edha89s(v=vs.100).aspx - ซึ่งจะเป็นประโยชน์อย่างยิ่งหากมีโอเวอร์โหลด ฉันใช้ชุดค่าผสม: s1.Nullify() ?? s2.Nullify()โดยstring Nullify(this s)คืนค่า a nullในกรณีที่สตริงว่าง
Kit

ปัญหาเดียว ฉันเพิ่งพบว่าตัวเองต้องการ ?? = และพบกระทู้นี้ในขณะที่ดูว่ามีวิธีการทำไหม (สถานการณ์: รหัสผ่านแรกโหลดกรณียกเว้นตอนนี้ฉันต้องการย้อนกลับไปและโหลดค่าเริ่มต้นเป็นสิ่งที่ยังไม่ได้โหลด)
Loren Pechtel

3

คือ ?? จำเป็นหรือคุณควรใช้ผู้ประกอบการที่ประกอบไปด้วย (ที่คุ้นเคยกับ)

คุณควรใช้สิ่งที่บ่งบอกความตั้งใจของคุณได้ดีที่สุด เนื่องจากมีเป็นผู้ประกอบการ null รวมกัน, ใช้มัน

ในทางกลับกันเนื่องจากเป็นผู้เชี่ยวชาญฉันจึงไม่คิดว่ามันมีประโยชน์อื่น ฉันต้องการเลือก||โอเปอเรเตอร์ที่เหมาะสมเช่นเดียวกับภาษาอื่น ๆ นี่จะเป็นการเพิ่มความสำคัญในการออกแบบภาษา แต่ ...


3

เย็น! นับฉันเป็นคนที่ไม่รู้เกี่ยวกับตัวดำเนินการรวมศูนย์ว่าง - นั่นเป็นสิ่งที่น่าสนใจ

ฉันพบว่าอ่านง่ายกว่าผู้ประกอบการที่ประกอบไปด้วย

สถานที่แรกที่นึกได้ว่าฉันควรใช้ที่ใดคือเก็บพารามิเตอร์เริ่มต้นไว้ในที่เดียว

public void someMethod( object parm2, ArrayList parm3 )
{ 
  someMethod( null, parm2, parm3 );
}
public void someMethod( string parm1, ArrayList parm3 )
{
  someMethod( parm1, null, parm3 );
}
public void someMethod( string parm1, object parm2, )
{
  someMethod( parm1, parm2, null );
}
public void someMethod( string parm1 )
{
  someMethod( parm1, null, null );
}
public void someMethod( object parm2 )
{
  someMethod( null, parm2, null );
}
public void someMethod( ArrayList parm3 )
{
  someMethod( null, null, parm3 );
}
public void someMethod( string parm1, object parm2, ArrayList parm3 )
{
  // Set your default parameters here rather than scattered through the above function overloads
  parm1 = parm1 ?? "Default User Name";
  parm2 = parm2 ?? GetCurrentUserObj();
  parm3 = parm3 ?? DefaultCustomerList;

  // Do the rest of the stuff here
}

2

บิตของกรณีการใช้งานที่แปลก แต่ฉันมีวิธีการที่IDisposableวัตถุอาจถูกส่งผ่านเป็น ARG (และถูกกำจัดโดยผู้ปกครอง) แต่อาจเป็นโมฆะ (และควรสร้างและกำจัดด้วยวิธีท้องถิ่น)

หากต้องการใช้งานรหัสก็ดูเหมือนว่า

Channel channel;
Authentication authentication;

if (entities == null)
{
    using (entities = Entities.GetEntities())
    {
        channel = entities.GetChannelById(googleShoppingChannelCredential.ChannelId);
        [...]
    }
}
else
{
    channel = entities.GetChannelById(googleShoppingChannelCredential.ChannelId);
    [...]
}

แต่ด้วยการรวมกันเป็นโมฆะกลายเป็น neater มาก

using (entities ?? Entities.GetEntities())
{
    channel = entities.GetChannelById(googleShoppingChannelCredential.ChannelId);
    [...]
}

0

ฉันเคยใช้สิ่งนี้:

for (int i = 0; i < result.Count; i++)
            {
                object[] atom = result[i];

                atom[3] = atom[3] ?? 0;
                atom[4] = atom[4] != null ? "Test" : string.Empty;
                atom[5] = atom[5] ?? "";
                atom[6] = atom[6] ?? "";
                atom[7] = atom[7] ?? "";
                atom[8] = atom[8] ?? "";
                atom[9] = atom[9] ?? "";
                atom[10] = atom[10] ?? "";
                atom[12] = atom[12] ?? false; 
            }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.