Làm thế nào để loại bỏ một cách rõ ràng một đối số?


99

Tôi đang gọi:

myResult = MakeMyCall(inputParams, out messages);

nhưng tôi không thực sự quan tâm đến các tin nhắn. Nếu đó là một tham số đầu vào, tôi không quan tâm, tôi sẽ chỉ truyền vào giá trị null. Nếu đó là sự trở lại mà tôi không quan tâm, tôi sẽ bỏ nó đi.

Có cách nào để làm điều gì đó tương tự với out, hay tôi cần khai báo một biến mà sau đó tôi sẽ bỏ qua?


Câu hỏi tương tự ở đây: stackoverflow.com/questions/2870544/…
Dunc,


Cảm ơn! Thật xấu hổ vì nó không có trong phiên bản mới nhất.
Andrew Ducker,

Câu trả lời:


99

Bắt đầu với C # 7.0, có thể tránh khai báo trước các tham số cũng như bỏ qua chúng.

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

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


1
Thật không may, điều này không được bao gồm trong C # 7 (tính đến tháng 4 năm 2017).
tia

2
@tia. Tôi đã cập nhật câu trả lời của mình. Rõ ràng, ký tự đại diện đã được thay đổi từ *thành _. Xin lỗi vì nó mất quá nhiều thời gian.
Nolonar

14
Họ lẽ ra phải mắc kẹt với ý tưởng sử dụng out voidcú pháp của mình, và dấu gạch dưới có vẻ như là một lựa chọn kỳ quặc.
David Anderson

1
@ DavidAnderson-DCOM Trong khi tôi không thích gạch dưới, tôi nghĩ họ cần tên loại để giải quyết quá tải.
Jonathan Allen

Có vẻ như nó vẫn tạo một tham số, vì tôi có thể thêm dòng _ = {a value};sau lời gọi hàm mà không gặp bất kỳ lỗi biên dịch nào.
Bip901

37

Thật không may, bạn bắt buộc phải vượt qua một cái gì đó vì phương thức này là bắt buộc để thiết lập nó. Vì vậy, bạn không thể gửi nullvì phương thức, được yêu cầu thiết lập, sẽ bị hỏng.

Một cách tiếp cận để che giấu sự xấu xí sẽ là bọc phương thức trong một phương thức khác có outtham số cho bạn như vậy:

String Other_MakeMyCall(String inputParams)
{
    String messages;

    return MakeMyCall(inputParams, out messages);
}

Sau đó, bạn có thể gọi Other_MakeMyCallmà không cần phải loay hoay với outcác thông số bạn không cần.


37

Bạn phải khai báo một biến mà sau đó bạn sẽ bỏ qua. Đây là trường hợp phổ biến nhất với mẫu TryParse (hoặc TryW Anything), khi nó được sử dụng để kiểm tra tính hợp lệ của đầu vào của người dùng (ví dụ: nó có thể được phân tích cú pháp thành một số không?) Mà không cần quan tâm đến giá trị được phân tích cú pháp thực tế.

Bạn đã sử dụng từ "vứt bỏ" trong câu hỏi, điều mà tôi nghi ngờ chỉ là không may - nhưng nếu tham số out thuộc loại triển khai IDisposable, bạn chắc chắn nên gọi Dispose trừ khi tài liệu phương thức nói rõ rằng việc nhận giá trị không mang lại quyền sở hữu. outMặc dù vậy, tôi không thể nhớ mình đã từng nhìn thấy một phương thức có tham số dùng một lần nào , vì vậy tôi hy vọng đây chỉ là một lựa chọn từ không may mắn.


Thêm một chống mẫu thực dụng
Jodrell

11

Nếu hàm gốc được khai báo như thế này:

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

Bạn có thể khai báo một phương thức mở rộng như sau:

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

Phương thức mở rộng sẽ hoạt động giống như một quá tải làm cho tham số out là tùy chọn.


4

Trình biên dịch Visual Basic thực hiện điều này bằng cách tạo một biến giả. C # có thể làm được, nếu bạn thuyết phục được Microsoft thì đó là một ý kiến ​​hay.


0

Nếu lớp của các nông messagescụ IDisposable, bạn không nên bỏ qua nó. Hãy xem xét điều gì đó giống như cách tiếp cận sau (có thể không chính xác về mặt cú pháp vì tôi đã không viết C # trong một thời gian):

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

Sau khi ra khỏi usingkhối, messagessẽ tự động được xử lý.


1
Hấp dẫn. Nhưng bạn không phải khởi tạo biến trong câu lệnh using?
OregonGhost

1
@OregonGhost: Đúng vậy. Và nếu bạn thay đổi giá trị của biến trong câu lệnh using, thì nó vẫn là giá trị ban đầu được loại bỏ.
Jon Skeet

@JonSkeet Không thể hiểu đó vẫn là giá trị ban đầu được xử lý.
Orkhan Alikhanov

@OrkhanAlikhanov: Về cơ bản, trình biên dịch lấy một bản sao của biến khi bắt đầu usingcâu lệnh. Vì vậy, việc thay đổi giá trị của biến đó trong khối không thay đổi đối tượng nào được xử lý.
Jon Skeet

Nhân tiện, nên có out messages.
Orkhan Alikhanov

0

Bạn phải chuyển một biến cho tham số out. Bạn không cần phải khởi tạo biến trước khi chuyển nó:

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

Thông thường, bạn chỉ có thể bỏ qua 'tin nhắn' sau cuộc gọi - trừ khi 'tin nhắn' cần loại bỏ vì lý do nào đó, chẳng hạn như việc sử dụng tài nguyên hệ thống hạn chế, trong trường hợp đó bạn nên gọi Dispose ():

messages.Dispose();

Nếu nó có thể sử dụng một lượng bộ nhớ đáng kể và nó sẽ vẫn ở trong phạm vi trong một thời gian, nó có thể phải được đặt thành null nếu nó là một kiểu tham chiếu hoặc một phiên bản mặc định mới nếu nó là một loại giá trị, để rác bộ sưu tập có thể lấy lại bộ nhớ:

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

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

0

Trong trường hợp này, tôi đã tạo một phương thức mở rộng chung cho ConcurrentDictionary không có phương thức Xóa hoặc Loại bỏ.

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

Khi được gọi từ một phiên bản của ConcurrentDictionary:

ClientList.TryRemoveIgnore(client.ClientId);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.