ฉันจะใช้ DateTime.TryParse กับ Nullable <DateTime> ได้อย่างไร


115

ฉันต้องการใช้เมธอด DateTime.TryParse เพื่อรับค่าวันที่และเวลาของสตริงเป็น Nullable แต่เมื่อฉันลองสิ่งนี้:

DateTime? d;
bool success = DateTime.TryParse("some date text", out (DateTime)d);

คอมไพเลอร์บอกฉัน

อาร์กิวเมนต์ 'out' ไม่ได้จัดเป็นตัวแปร

ไม่แน่ใจว่าต้องทำอะไรที่นี่ ฉันได้ลองแล้ว:

out (DateTime)d.Value 

และไม่ได้ผลเช่นกัน ความคิดใด ๆ ?

คำตอบ:


123
DateTime? d=null;
DateTime d2;
bool success = DateTime.TryParse("some date text", out d2);
if (success) d=d2;

(อาจมีวิธีแก้ปัญหาที่หรูหรากว่านี้ แต่ทำไมคุณไม่ทำบางอย่างตามข้างบนล่ะ


3
คุณพูดถูกฉันกำลังมองหาหนึ่งซับในมากกว่านี้ แต่ฉันคิดว่ามันจะทำได้ ไม่ชอบสร้างตัวแปร temp นั้นรู้สึกยุ่ง : - / ดูเหมือนว่าสถานการณ์นี้ควรได้รับการสนับสนุนที่ดีกว่านี้
Brian Sullivan

1
ดูคำแนะนำของ Binary Worrier ในการ psuedo-inline ในวิธีการขยาย
David Alpert

4
ทำไมคุณจึงส่ง DateTime เป็น DateTime คุณไม่จำเป็นต้องอ่าน d2 ก่อนที่จะส่งไปยัง TryParse
Aaron Powell

@Slace - ฉันอัปเดตคำตอบเพื่อรวมข้อเสนอแนะของคุณ
Drew Noakes

@ Jason Kealey ฉันหวังว่าสิ่งนี้จะถูกนำมาใช้ใน VS2012 แล้วมิฉะนั้นฉันจะต้องใช้โค้ดที่ดีนี้ต่อไป
Pimenta

161

ดังที่ Jason กล่าวไว้คุณสามารถสร้างตัวแปรให้ถูกประเภทและส่งผ่านไปได้ คุณอาจต้องการห่อหุ้มด้วยวิธีการของคุณเอง:

public static DateTime? TryParse(string text)
{
    DateTime date;
    if (DateTime.TryParse(text, out date))
    {
        return date;
    }
    else
    {
        return null;
    }
}

... หรือถ้าคุณชอบตัวดำเนินการตามเงื่อนไข:

public static DateTime? TryParse(string text)
{
    DateTime date;
    return DateTime.TryParse(text, out date) ? date : (DateTime?) null;
}

หรือใน C # 7:

public static DateTime? TryParse(string text) =>
    DateTime.TryParse(text, out var date) ? date : (DateTime?) null;

5
ฉันอาจไม่ควรเถียงกับ The Skeet แต่ ... คุณควรเรียก method ของคุณว่า Parse เนื่องจากฉันคาดหวังว่าเมธอดที่เรียกว่า TryParse จะทำตามหลักการของ TryParse และส่งคืนบูลีน ;-)
Myster

@ นางนางรม: ไม่ว่าในกรณีใดก็ตามจะไม่เป็นไปตามอนุสัญญาที่มีอยู่แน่นอน - ผู้ที่เคยParseคาดหวังว่ามันจะกลับมาDateTimeและโยนข้อยกเว้นสำหรับความล้มเหลวใช่ไหม? แต่ใช่คุณสามารถทำอะไรก็ได้ที่คุณต้องการ ... และใน Noda Time ฉันได้ตั้งชื่อวิธีการที่เกี่ยวข้องParseแทน
Jon Skeet

1
elseคำหลักที่ไม่จำเป็น (ในตัวอย่างแรกของคุณ) ตั้งแต่จุดสิ้นสุดของifบล็อกไม่สามารถเข้าถึงได้
Jeppe Stig Nielsen

1
@JeppeStigNielsen: ใช่มันไม่จำเป็น - แต่มันอาจจะดีกว่าสำหรับความสมมาตรในโวหาร มันเป็นแค่ความชอบส่วนตัว (และฉันก็ไม่ลงรอยกันเหมือนกัน ... )
Jon Skeet

3
@Kiquenet: การใช้ else ทำให้ชัดเจนขึ้นว่าจะใช้เส้นทางใดเส้นทางหนึ่งและทั้งสองจะกลับมา ฉันต่อต้านรหัสที่ซ้อนกันอย่างหนาแน่น แต่ในกรณีนี้มันไม่ใช่ปัญหา IMO
Jon Skeet

20

นี่คือฉบับย่อเล็กน้อยของสิ่งที่ Jason แนะนำ:

DateTime? d; DateTime dt;
d = DateTime.TryParse(DateTime.Now.ToString(), out dt)? dt : (DateTime?)null;

18

คุณไม่สามารถเพราะเป็นชนิดที่แตกต่างกันไปNullable<DateTime> DateTimeคุณต้องเขียนฟังก์ชันของคุณเองจึงจะทำได้

public bool TryParse(string text, out Nullable<DateTime> nDate)
{
    DateTime date;
    bool isParsed = DateTime.TryParse(text, out date);
    if (isParsed)
        nDate = new Nullable<DateTime>(date);
    else
        nDate = new Nullable<DateTime>();
    return isParsed;
}

หวังว่านี่จะช่วยได้ :)

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

ปล. Bad Hoor ที่มีปัญหาคือเพื่อนเก่า :)


คุณไม่ต้องการเริ่มต้นวันที่ [ในขณะที่คุณกำลังใช้มันเป็นพารามิเตอร์นอก] ตกลงฉันจะเลิกจู้จี้จุกจิก!
Ruben Bartelink

ไม่มีคอมไพเลอร์กับฉัน แต่เนื่องจาก DateTime เป็นประเภทค่าวิธีการส่วนขยายจะคอมไพล์หรือไม่
Ruben Bartelink

ผลลัพธ์จะไม่กลับมาเว้นแต่คุณจะทำมันออกมา - [TestFixture] คลาสสาธารณะ WhenExtending {[Test] โมฆะสาธารณะ TryParseShouldWork () {DateTime? x = null; var res = Externders.TryParse (x, "1/1/1990"); Assert.IsTrue (res)
Ruben Bartelink

; ยืนยันว่า (x! = null); }} ล้มเหลวใน Assert นั่นคือผลลัพธ์ไม่ได้รับการแก้ไขเนื่องจาก DateTime เป็นประเภทค่า (ซึ่งเป็นคำถามที่กำจัดวัชพืชได้ดีบนหน้าจอโทรศัพท์เสมอ: D)
Ruben Bartelink

(obv ตัวแรก (ไม่ใช่ส่วนขยาย) จะใช้งานได้ แต่ควรจะออกไม่ใช่อ้างอิง - และคุณควรลบผลลัพธ์หากไม่สามารถปรับให้เข้ากับ TryXXX API โดยทั่วไปได้ - ค่อนข้างแน่ใจว่า FDG กล่าวถึงสิ่งนั้นผู้ชายฉัน ฉันจู้จี้จุกจิก!
Ruben Bartelink

4

แล้วการสร้างวิธีการขยายล่ะ?

public static class NullableExtensions
{
    public static bool TryParse(this DateTime? dateTime, string dateString, out DateTime? result)
    {
        DateTime tempDate;
        if(! DateTime.TryParse(dateString,out tempDate))
        {
            result = null;
            return false;
        }

        result = tempDate;
        return true;

    }
}

2
พารามิเตอร์ตัวแรกdateTimeคืออะไร? มันไม่เคยใช้
Mike Zboray

1
@mikez - นั่นคือวิธีการทำงานของวิธีการส่วนขยายซึ่งคอมไพเลอร์ใช้เพื่อให้รู้ว่าควรเป็นวิธีการขยาย
Erik Funkenbusch

3
@MystereMan ฉันรู้ว่าวิธีการขยายคืออะไร DateTime? TryParse(this string dateString)ลายเซ็นที่เหมาะสมสำหรับวิธีขยายจะเป็น การใช้งานนี้เป็นเรื่องแปลกประหลาด
Mike Zboray

3
@mikez - แล้วทำไมถามว่าทำเพื่ออะไร? เหตุใดเนมสเปซสตริงจึงก่อมลพิษเมื่อคุณต้องการเพียงวันที่และเวลา จุดประสงค์คือเพื่อให้อะนาล็อกเป็น DateTime.TryParse นั่นคือ DateTime?
TryParse

1
@ErikFunkenbusch วิธีขยายนี้จะไม่อนุญาตให้มีการโทรไวยากรณ์เหมือนหรือ(DateTime?).TryParse( ... ) Nullable<DateTime>.TryParse( ... )ดังนั้น mike z ถูกต้องนี่เป็นลายเซ็นโง่ ๆ สำหรับวิธีการนี้
Jeppe Stig Nielsen

1

ฉันไม่เห็นว่าทำไม Microsoft ไม่จัดการเรื่องนี้ วิธียูทิลิตี้เล็ก ๆ น้อย ๆ ที่ชาญฉลาดในการจัดการกับสิ่งนี้ (ฉันมีปัญหากับ int แต่การแทนที่ int ด้วย DateTime จะให้ผลเหมือนกันอาจเป็น .....

    public static bool NullableValueTryParse(string text, out int? nInt)
    {
        int value;
        if (int.TryParse(text, out value))
        {
            nInt = value;
            return true;
        }
        else
        {
            nInt = null;
            return false;
        }
    }

1

นี่คือซับที่คุณกำลังมองหาสำหรับ:

DateTime? d = DateTime.TryParse("some date text", out DateTime dt) ? dt : null;

หากคุณต้องการทำให้เป็นวิธีการขยายหลอกของ TryParse ที่เหมาะสมคุณสามารถทำได้:

public static bool TryParse(string text, out DateTime? dt)
{
    if (DateTime.TryParse(text, out DateTime date))
    {
        dt = date;
        return true;
    }
    else
    {
        dt = null;
        return false;
    }
}

@robnick แตกต่างจากที่ฉันพูดอย่างไร?
cpcolella

1
ไม่สนใจความคิดเห็นก่อนหน้าของฉัน (ฉันได้เพิ่มคะแนนการแก้ปัญหาของคุณแล้ว!) สำหรับ C # ล่าสุดฉันต้องการส่ง null: DateTime? d = DateTime.TryParse (blah ออก DateTime dt)? dt: (DateTime?) null;
robnick

1

นี่คือโซลูชันบรรทัดเดียว:

DateTime? d = DateTime.TryParse("text", out DateTime parseDate) ? parseDate : (DateTime?)null;

-3

หรือหากคุณไม่กังวลกับข้อยกเว้นที่อาจเกิดขึ้นคุณสามารถเปลี่ยน TryParse สำหรับ Parse:

DateTime? d = DateTime.Parse("some valid text");

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

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