Bagaimana cara secara eksplisit membuang argumen keluar?


99

Saya sedang menelepon:

myResult = MakeMyCall(inputParams, out messages);

tapi saya sebenarnya tidak peduli dengan pesannya. Jika itu adalah parameter input, saya tidak peduli, saya hanya akan memberikan null. Jika itu adalah pengembalian, saya tidak peduli, saya akan membiarkannya begitu saja.

Apakah ada cara untuk melakukan sesuatu yang serupa dengan out, atau apakah saya perlu mendeklarasikan variabel yang kemudian akan saya abaikan?


Pertanyaan serupa di sini: stackoverflow.com/questions/2870544/…
Dunc


Terima kasih! Sayang itu bukan versi terbaru.
Andrew Ducker

Jawaban:


99

Dimulai dengan C # 7.0, adalah mungkin untuk menghindari pernyataan parameter sebelumnya serta mengabaikannya.

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}");
}

Sumber: https://blogs.msdn.microsoft.com/dotnet/2017/03/09/new-features-in-c-7-0/


1
Sayangnya, ini tidak termasuk dalam C # 7 (per Apr 2017).
tia

2
@tia. Saya telah memperbarui jawaban saya. Rupanya, karakter wildcard diubah dari *menjadi _. Maaf butuh waktu lama.
Nolonar

14
Mereka seharusnya terjebak dengan idenya untuk digunakan out voiduntuk sintaks, dan garis bawah tampak seperti pilihan yang aneh.
David Anderson

1
@ DavidAnderson-DCOM Meskipun saya bukan penggemar garis bawah, saya rasa mereka membutuhkan nama tipe untuk resolusi yang berlebihan.
Jonathan Allen

Sepertinya masih membuat parameter, karena saya dapat menambahkan baris _ = {a value};setelah pemanggilan fungsi tanpa kesalahan kompilasi.
Bip901

37

Sayangnya Anda diharuskan untuk melewatkan sesuatu karena diperlukan metode untuk mengaturnya. Jadi, Anda tidak dapat mengirim nullkarena metode, jika diminta untuk mengaturnya, akan meledak.

Salah satu pendekatan untuk menyembunyikan keburukan adalah dengan membungkus metode dengan metode lain yang melakukan outparameter untuk Anda seperti:

String Other_MakeMyCall(String inputParams)
{
    String messages;

    return MakeMyCall(inputParams, out messages);
}

Kemudian Anda dapat menelepon Other_MakeMyCalltanpa harus mengutak-atik outparameter yang tidak Anda perlukan.


37

Anda harus mendeklarasikan variabel yang kemudian akan Anda abaikan. Hal ini paling sering terjadi pada pola TryParse (atau TryWhatever), ketika digunakan untuk menguji validitas input pengguna (misalnya, apakah dapat diuraikan sebagai angka?) Tanpa mempedulikan nilai parsing yang sebenarnya.

Anda menggunakan kata "membuang" dalam pertanyaan, yang saya curigai tidak menguntungkan - tetapi jika parameter out adalah tipe yang mengimplementasikan IDisposable, Anda pasti harus memanggil Buang kecuali jika dokumentasi metode secara eksplisit menyatakan bahwa menerima nilai tidak memberikan kepemilikan. Saya tidak ingat pernah melihat metode dengan outparameter sekali pakai , jadi saya berharap ini hanya pilihan kata yang tidak menguntungkan.


Lebih dari anti-pola pragmatis
Jodrell

11

Jika fungsi asli dideklarasikan seperti ini:

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

Anda dapat mendeklarasikan metode ekstensi seperti ini:

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

Metode ekstensi akan berperilaku seperti beban berlebih yang membuat parameter keluar menjadi opsional.


4

Kompiler Visual Basic melakukan ini dengan membuat variabel dummy. C # bisa melakukannya, jika Anda bisa meyakinkan Microsoft itu ide yang bagus.


0

Jika kelas messagesmengimplementasikan IDisposable, Anda tidak boleh mengabaikannya. Pertimbangkan sesuatu seperti pendekatan berikut (mungkin tidak benar secara sintaksis karena saya sudah lama tidak menulis C #):

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

Begitu berada di luar usingblok, messagesakan dibuang secara otomatis.


1
Menarik. Tapi bukankah Anda harus menginisialisasi variabel dalam pernyataan use?
OregonGhost

1
@OregonGhost: Ya, benar. Dan jika Anda mengubah nilai variabel dalam pernyataan use, itu masih nilai asli yang dibuang.
Jon Skeet

@JonSkeet Tidak dapat memahami bahwa itu masih nilai asli yang dibuang.
Orkhan Alikhanov

@OrkhanAlikhanov: Pada dasarnya kompilator mengambil salinan variabel di awal usingpernyataan. Jadi mengubah nilai variabel itu di dalam blok tidak mengubah objek mana yang dibuang.
Jon Skeet

Ngomong-ngomong, seharusnya ada out messages.
Orkhan Alikhanov

0

Anda harus meneruskan variabel untuk parameter keluar. Anda tidak perlu menginisialisasi variabel sebelum meneruskannya:

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

Biasanya, Anda bisa mengabaikan 'messages' setelah panggilan - kecuali 'messages' perlu dibuang karena alasan tertentu, seperti penggunaan sumber daya sistem yang terbatas, dalam hal ini Anda harus memanggil Dispose ():

messages.Dispose();

Jika mungkin menggunakan sejumlah besar memori dan akan tetap dalam ruang lingkup untuk sementara waktu, itu mungkin harus disetel ke null jika itu adalah tipe referensi atau ke contoh default baru jika itu adalah tipe nilai, sehingga sampah kolektor dapat memperoleh kembali memori:

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

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

0

Dalam hal ini saya membuat metode ekstensi generik untuk ConcurrentDictionary yang tidak memiliki metode Hapus atau Hapus.

//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);
}

Saat dipanggil dari instance ConcurrentDictionary:

ClientList.TryRemoveIgnore(client.ClientId);
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.