จะทิ้งข้อโต้แย้งอย่างชัดเจนได้อย่างไร?


105

ฉันกำลังโทร:

myResult = MakeMyCall(inputParams, out messages);

แต่ฉันไม่สนใจข้อความจริงๆ หากเป็นพารามิเตอร์อินพุตฉันไม่สนใจฉันก็แค่ส่งเป็นโมฆะ ถ้าเป็นการกลับมาฉันไม่สนใจฉันก็ทิ้งมันไป

มีวิธีทำสิ่งที่คล้ายกันกับการออกหรือไม่หรือฉันต้องประกาศตัวแปรที่ฉันจะเพิกเฉย


คำถามที่คล้ายกันที่นี่: stackoverflow.com/questions/2870544/…
Dunc


ขอบคุณ! อัปยศไม่ได้อยู่ในเวอร์ชันล่าสุด
Andrew Ducker

คำตอบ:


107

เริ่มต้นด้วย C # 7.0 เป็นไปได้ที่จะหลีกเลี่ยงการประกาศพารามิเตอร์ไว้ล่วงหน้ารวมทั้งละเว้นพารามิเตอร์เหล่านี้

public void PrintCoordinates(Point p)
{
    p.GetCoordinates(out int x, out int y);
    WriteLine($"({x}, {y})");
}

public void PrintXCoordinate(Point p)
{
    p.GetCoordinates(out int x, out _); // I only care about x
    WriteLine($"{x}");
}

ที่มา: https://blogs.msdn.microsoft.com/dotnet/2017/03/09/new-features-in-c-7-0/


1
น่าเสียดายที่สิ่งนี้ไม่รวมอยู่ใน C # 7 (ณ เมษายน 2017)
เที

2
@tia. ฉันได้อัปเดตคำตอบแล้ว เห็นได้ชัดว่าอักขระตัวแทนก็เปลี่ยนจากการ* _ขออภัยที่ใช้เวลานานมาก
Nolonar

14
พวกเขาควรจะติดอยู่กับความคิดที่จะใช้out voidสำหรับไวยากรณ์และขีดล่างดูเหมือนจะเป็นทางเลือกที่แปลก
David Anderson

1
@ DavidAnderson-DCOM ในขณะที่ฉันไม่ใช่แฟนของขีดล่างฉันคิดว่าพวกเขาต้องการชื่อประเภทสำหรับความละเอียดเกินพิกัด
Jonathan Allen

ดูเหมือนว่ามันยังคงสร้างพารามิเตอร์อยู่เพราะฉันสามารถเพิ่มบรรทัด_ = {a value};หลังจากเรียกฟังก์ชันได้โดยไม่มีข้อผิดพลาดในการคอมไพล์
Bip901

37

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

วิธีหนึ่งในการซ่อนความอัปลักษณ์คือการรวมเมธอดไว้ในวิธีอื่นที่สร้างoutพารามิเตอร์ให้คุณเช่น:

String Other_MakeMyCall(String inputParams)
{
    String messages;

    return MakeMyCall(inputParams, out messages);
}

จากนั้นคุณสามารถโทรได้Other_MakeMyCallโดยไม่ต้องoutยุ่งกับพารามิเตอร์ที่คุณไม่ต้องการ


37

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

คุณใช้คำว่า "ทิ้ง" ในคำถามซึ่งฉันสงสัยว่าเป็นเพียงโชคร้าย - แต่ถ้าพารามิเตอร์ out เป็นประเภทที่ใช้ IDisposable คุณควรเรียก Dispose อย่างแน่นอนเว้นแต่เอกสารวิธีการจะระบุไว้อย่างชัดเจนว่าการรับค่าไม่ได้ให้ผล ความเป็นเจ้าของ. ฉันจำไม่ได้ว่าเคยเห็นวิธีการที่มีoutพารามิเตอร์แบบใช้แล้วทิ้งดังนั้นฉันหวังว่านี่จะเป็นเพียงตัวเลือกคำที่โชคร้าย


เพิ่มเติมเกี่ยวกับรูปแบบการต่อต้านในทางปฏิบัติ
Jodrell

11

หากฟังก์ชันดั้งเดิมถูกประกาศเช่นนี้:

class C
{
    public Result MakeMyCall(Object arg, out List<String> messages);
}

คุณสามารถประกาศวิธีการขยายได้ดังนี้:

static class CExtension
{
    public static Result MakeMyCall(this C obj, Object arg)
    {
        List<String> unused;
        return obj.MakeMyCall(arg, out unused);
    }
}

เมธอดส่วนขยายจะทำงานเหมือนโอเวอร์โหลดที่ทำให้พารามิเตอร์ out เป็นทางเลือก


4

คอมไพเลอร์ Visual Basic ทำได้โดยการสร้างตัวแปรจำลอง C # สามารถทำได้ถ้าคุณสามารถโน้มน้าวให้ Microsoft เป็นความคิดที่ดี


0

หากคลาสของmessagesการใช้งานIDisposableคุณไม่ควรเพิกเฉย ลองพิจารณาแนวทางต่อไปนี้ (อาจไม่ถูกต้องตามหลักไวยากรณ์เนื่องจากฉันไม่ได้เขียน C # มาสักพักแล้ว):

using (FooClass messages) {
    myResult = MakeMyCall(inputParams, messages);
}

เมื่ออยู่นอกusingด่านmessagesจะถูกกำจัดโดยอัตโนมัติ


1
น่าสนใจ. แต่คุณไม่ต้องเริ่มต้นตัวแปรในคำสั่งใช้หรือไม่?
OregonGhost

1
@OregonGhost: ใช่คุณทำ และถ้าคุณเปลี่ยนค่าของตัวแปรภายในคำสั่งใช้ก็จะยังคงเป็นค่าเดิมที่ถูกกำจัด
Jon Skeet

@JonSkeet ไม่สามารถเข้าใจได้ว่ามันยังคงเป็นค่าดั้งเดิมที่ถูกกำจัด
Orkhan Alikhanov

@OrkhanAlikhanov: โดยทั่วไปแล้วคอมไพเลอร์จะคัดลอกตัวแปรที่จุดเริ่มต้นของusingคำสั่ง ดังนั้นการเปลี่ยนค่าของตัวแปรนั้นภายในบล็อกจะไม่เปลี่ยนวัตถุที่จะกำจัด
Jon Skeet

out messagesโดยวิธีการที่ควรจะมี
Orkhan Alikhanov

0

คุณต้องส่งผ่านตัวแปรสำหรับพารามิเตอร์ out คุณไม่จำเป็นต้องเริ่มต้นตัวแปรก่อนที่จะส่งผ่าน:

MyMessagesType messages;
myResult = MakeMyCall(inputParams, out messages); 

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

messages.Dispose();

หากอาจใช้หน่วยความจำจำนวนมากและจะยังคงอยู่ในขอบเขตระยะหนึ่งก็ควรตั้งค่าเป็น null หากเป็นประเภทอ้างอิงหรือเป็นอินสแตนซ์เริ่มต้นใหม่หากเป็นประเภทค่าเพื่อให้ขยะ นักสะสมสามารถเรียกคืนหน่วยความจำ:

messages = null; // Allow GC to reclaim memory for reference type.

messages = new MyMessageType(); // Allow GC to reclaim memory for value type.

0

ในกรณีนี้ฉันสร้างเมธอดส่วนขยายทั่วไปสำหรับ ConcurrentDictionary ที่ไม่มีเมธอด Delete หรือ Remove

//Remove item from list and ignore reference to removed item
public static void TryRemoveIgnore<K,T>(this ConcurrentDictionary<K,T> dictionary, K key)
{
    T CompletelyIgnored;
    dictionary.TryRemove(key, out CompletelyIgnored);
}

เมื่อเรียกจากอินสแตนซ์ของ ConcurrentDictionary:

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