2010-05-05 43 views
10

Khi tôi phải viết phương pháp mà trở lại hai giá trị, tôi thường đi về nó như trong đoạn mã sau đó trả về một List<string>. Hoặc nếu tôi phải quay lại, ví dụ: số id và chuỗi, sau đó tôi trả lại List<object> rồi chọn chúng ra với số chỉ sốrecast giá trị.Cách tốt nhất để trả lại hai giá trị từ một phương thức là gì?

Việc tính lại và tham chiếu theo chỉ mục này có vẻ không phù hợp vì vậy tôi muốn phát triển một thói quen mới cho các phương thức trả về hai giá trị. Mô hình tốt nhất cho điều này là gì?

using System; 
using System.Collections.Generic; 
using System.Linq; 

namespace MultipleReturns 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      string extension = "txt"; 

      { 
       List<string> entries = GetIdCodeAndFileName("first.txt", extension); 
       Console.WriteLine("{0}, {1}", entries[0], entries[1]); 
      } 

      { 
       List<string> entries = GetIdCodeAndFileName("first", extension); 
       Console.WriteLine("{0}, {1}", entries[0], entries[1]); 
      } 

      Console.ReadLine(); 
     } 

     /// <summary> 
     /// gets "first.txt", "txt" and returns "first", "first.txt" 
     /// gets "first", "txt" and returns "first", "first.txt" 
     /// it is assumed that extensions will always match 
     /// </summary> 
     /// <param name="line"></param> 
     public static List<string> GetIdCodeAndFileName(string line, string extension) 
     { 
      if (line.Contains(".")) 
      { 
       List<string> parts = line.BreakIntoParts("."); 
       List<string> returnItems = new List<string>(); 
       returnItems.Add(parts[0]); 
       returnItems.Add(line); 
       return returnItems; 
      } 
      else 
      { 
       List<string> returnItems = new List<string>(); 
       returnItems.Add(line); 
       returnItems.Add(line + "." + extension); 
       return returnItems; 
      } 
     } 

    } 

    public static class StringHelpers 
    { 
     public static List<string> BreakIntoParts(this string line, string separator) 
     { 
      if (String.IsNullOrEmpty(line)) 
       return null; 
      else 
      { 
       return line.Split(new string[] { separator }, StringSplitOptions.None).Select(p => p.Trim()).ToList(); 
      } 
     } 
    } 
} 

Added:

Ok, nhờ mọi người, tôi thích "trả về một lớp tùy chỉnh" câu trả lời tốt nhất, không bao giờ thực sự nghĩ out là dễ đọc, có vẻ như một hack để tôi trả lại biến đầu tiên theo một cách và biến thứ hai khác, đây là việc tái cấu trúc của tôi trở về lớp tùy chỉnh:

using System; 
using System.Collections.Generic; 
using System.Linq; 

namespace MultipleReturns 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      string extension = "txt"; 

      { 
       IdCodeFileNamePair pair = GetIdCodeAndFileName("first.txt", extension); 
       Console.WriteLine("{0}, {1}", pair.IdCode, pair.FileName); 
      } 

      { 
       IdCodeFileNamePair pair = GetIdCodeAndFileName("first", extension); 
       Console.WriteLine("{0}, {1}", pair.IdCode, pair.FileName); 
      } 

      Console.ReadLine(); 
     } 

     /// <summary> 
     /// gets "first.txt", "txt" and returns "first", "first.txt" 
     /// gets "first", "txt" and returns "first", "first.txt" 
     /// it is assumed that extensions will always match 
     /// </summary> 
     /// <param name="line"></param> 
     public static IdCodeFileNamePair GetIdCodeAndFileName(string line, string extension) 
     { 
      if (line.Contains(".")) 
      { 
       List<string> parts = line.BreakIntoParts("."); 
       List<string> returnItems = new List<string>(); 
       return new IdCodeFileNamePair { IdCode = parts[0], FileName = line }; 
      } 
      else 
      { 
       List<string> returnItems = new List<string>(); 
       return new IdCodeFileNamePair { IdCode = line, FileName = line + "." + extension }; 
      } 
     } 

    } 

    public static class StringHelpers 
    { 
     public static List<string> BreakIntoParts(this string line, string separator) 
     { 
      if (String.IsNullOrEmpty(line)) 
       return null; 
      else 
      { 
       return line.Split(new string[] { separator }, StringSplitOptions.None).Select(p => p.Trim()).ToList(); 
      } 
     } 
    } 

    public class IdCodeFileNamePair 
    { 
     public string IdCode { get; set; } 
     public string FileName { get; set; } 
    } 
} 
+0

@tehMick Không thực sự chắc chắn lý do bạn tự mình lấy thẻ để xóa các thẻ đó? Họ dường như có liên quan đến tôi. –

+8

Đừng quên giải pháp tốt nhất: tái cấu trúc mã để mọi phương thức đều trả về một cách hợp lý một điều. Thực tế là bạn có một phương thức trả về hai kết quả là một lá cờ đỏ chỉ ra rằng phương thức này có thể hưởng lợi từ việc tái cấu trúc. –

Trả lời

12

tôi thích hoặc để tạo ra một lớp nhẹ với hai thuộc tính (xem bên dưới), hoặc sử dụng một tuple (bây giờ đã có nướng vào khuôn khổ trong .NET 4 nhưng không khó để viết riêng của bạn)

class MyReturnValue 
{ 
    public string Id { get; set; } 
    public string Name { get; set; } 
} 
2

Sử dụng từ khóa out

http://msdn.microsoft.com/en-us/library/ee332485.aspx

Đây là cách tốt hơn so với đúc yếu tố cụ thể của một danh sách các đối tượng.

+0

Làm thế nào để bạn chuyển kết quả gọn gàng vào một cuộc gọi phương thức khác? –

+0

'int a; Foo (ra ngoài); Bar (a); ' Tóm lại, bạn không. 'out' không thanh lịch, nhưng đôi khi cần thiết. –

+0

@John: Tên tệp phải là một tham số riêng biệt cho mọi cuộc gọi phương thức tiếp theo. Điều này chỉ là gọn gàng như bất cứ điều gì khác. –

0

Làm thế nào về một mẫu Pair<T,V>? Tất nhiên bạn có thể xây dựng các kiểu dữ liệu tùy chỉnh cho điều này nếu các kiểu dữ liệu tương tự sẽ được truyền đi xung quanh, nhưng nó không phải là chung chung.

(Hoặc có lẽ không C# cho phép bạn tạo ra các lớp on-the-fly cập nhật: ok bỏ qua điều này chút)

+0

Có bạn có thể tạo một lớp trên bay, nhưng nó phải nằm trong phạm vi địa phương, vì vậy nó không thể là sự trở lại giá trị của một phương thức. –

8

Bạn có thể trả về một tuple, bắt đầu với 4.0.

+1

Đã làm cho cộng đồng wiki này vô tình? Bạn không tích luỹ đại diện cho các bài đăng CW! –

1

Tại sao không public static void GetIdCodeAndFileName(string line, string extension, out string id, out string fileName)?

+0

Làm cách nào để chuyển kết quả gọn gàng vào một cuộc gọi phương thức khác? –

+0

@John: Tên tệp phải là một tham số riêng biệt cho mọi cuộc gọi phương thức tiếp theo. Điều này chỉ là gọn gàng như bất cứ điều gì khác. –

+0

Trong ví dụ này có lẽ, không phải là câu hỏi tổng quát hơn? –

0

Chỉ đơn giản là không phải là một cách thanh lịch để trả về hai giá trị trong C#. Mặc dù tôi chắc chắn nghĩ rằng việc sử dụng các thông số out tốt hơn là trả về một số List, điều đó không thể duy trì hoặc có thể đọc được. Các nhà phát triển C# mong đợi out, nó được hỗ trợ trực tiếp bởi ngôn ngữ, và nó cũng hiểu những gì nó đang làm.

Bắt đầu từ 4.0, bạn có thể sử dụng một Tuple để thay thế.

1

Tôi hoặc sử dụng các tham số ngoài hoặc tạo cấu trúc với các thuộc tính (đối với cú pháp trình khởi tạo thuộc tính) và trả về điều đó. Tạo cấu trúc/lớp tùy chỉnh có lợi thế về việc đặt tên biến có thể khớp với dữ liệu được truyền. Điều này làm cho mã dễ đọc hơn.

IdAndString GetIDAndString() 
{ 
    return new IdAndString() 
    { 
     ID = 1, 
     Str = "123" 
    }; 
} 

struct IdAndString 
{ 
    public int ID { get; set; } 
    public string Str { get; set; } 
} 
2

Một tùy chọn khác là trả về KeyValuePair<int, string>.

1

Tôi khuyên bạn nên sử dụng đối tượng có trọng lượng nhẹ như Mark được đề xuất. Nhưng cũng có những mẫu khác.

Một cách tiếp cận đơn giản khác là sử dụng cuộc gọi bằng thuộc tính tham chiếu. Giống như, người gọi sẽ gửi một mảng trống như một tham số, sẽ được điền bởi hàm.

Các vấn đề liên quan