Làm cách nào để tìm một phần tử cụ thể trong Danh sách <T>?


114

Ứng dụng của tôi sử dụng một danh sách như sau:

List<MyClass> list = new List<MyClass>();

Sử dụng Addphương thức này, một phiên bản khác của MyClassđược thêm vào danh sách.

MyClass cung cấp, trong số những phương pháp sau:

public void SetId(String Id);
public String GetId();

Làm thế nào tôi có thể tìm thấy một phiên bản cụ thể của MyClassbằng cách sử dụng GetIdphương pháp? Tôi biết có Findphương pháp này, nhưng tôi không biết liệu điều này có hiệu quả ở đây không ?!

Câu trả lời:


263

Sử dụng biểu thức lambda

MyClass result = list.Find(x => x.GetId() == "xy");

Lưu ý: C # có một cú pháp tích hợp cho các thuộc tính. Thay vì viết các phương thức getter và setter (như bạn có thể quen với Java), hãy viết

private string _id;
public string Id
{
    get
    {
        return _id;
    }
    set
    {
        _id = value;
    }
}

valuelà một từ khóa theo ngữ cảnh chỉ được biết đến trong bộ truy cập tập hợp. Nó đại diện cho giá trị được gán cho thuộc tính.

Vì mẫu này thường được sử dụng, C # cung cấp các thuộc tính được triển khai tự động . Chúng là một phiên bản ngắn của đoạn mã trên; tuy nhiên, biến ủng hộ bị ẩn và không thể truy cập được (tuy nhiên, nó có thể truy cập từ bên trong lớp trong VB).

public string Id { get; set; }

Bạn có thể chỉ cần sử dụng các thuộc tính như thể bạn đang truy cập một trường:

var obj = new MyClass();
obj.Id = "xy";       // Calls the setter with "xy" assigned to the value parameter.
string id = obj.Id;  // Calls the getter.

Sử dụng thuộc tính, bạn sẽ tìm kiếm các mục trong danh sách như thế này

MyClass result = list.Find(x => x.Id == "xy"); 

Bạn cũng có thể sử dụng các thuộc tính được triển khai tự động nếu bạn cần thuộc tính chỉ đọc:

public string Id { get; private set; }

Điều này cho phép bạn thiết lập Idbên trong lớp chứ không phải từ bên ngoài. Nếu bạn cần thiết lập nó trong các lớp dẫn xuất, bạn cũng có thể bảo vệ setter

public string Id { get; protected set; }

Và cuối cùng, bạn có thể khai báo thuộc tính virtualvà ghi đè chúng trong các lớp dẫn xuất, cho phép bạn cung cấp các triển khai khác nhau cho getters và setters; cũng như đối với các phương thức ảo thông thường.


Kể từ C # 6.0 (Visual Studio 2015, Roslyn), bạn có thể viết thuộc tính tự động chỉ getter với trình khởi tạo nội tuyến

public string Id { get; } = "A07"; // Evaluated once when object is initialized.

Thay vào đó, bạn cũng có thể khởi tạo các thuộc tính chỉ getter trong hàm tạo. Thuộc tính tự động chỉ getter là thuộc tính chỉ đọc thực sự , không giống như các thuộc tính được triển khai tự động với trình cài đặt riêng.

Điều này cũng hoạt động với các thuộc tính tự động đọc-ghi:

public string Id { get; set; } = "A07";

Bắt đầu với C # 6.0, bạn cũng có thể viết các thuộc tính dưới dạng các thành viên thân biểu thức

public DateTime Yesterday => DateTime.Date.AddDays(-1); // Evaluated at each call.
// Instead of
public DateTime Yesterday { get { return DateTime.Date.AddDays(-1); } }

Xem: Nền tảng biên dịch .NET ("Roslyn")
         Các tính năng ngôn ngữ mới trong C # 6

Bắt đầu với C # 7.0 , cả hai, getter và setter, đều có thể được viết bằng các phần thân biểu thức:

public string Name
{
    get => _name;                                // getter
    set => _name = value;                        // setter
}

Lưu ý rằng trong trường hợp này, setter phải là một biểu thức. Nó không thể là một tuyên bố. Ví dụ trên hoạt động, bởi vì trong C #, một phép gán có thể được sử dụng như một biểu thức hoặc như một câu lệnh. Giá trị của một biểu thức gán là giá trị được gán trong đó bản thân phép gán là một tác dụng phụ. Điều này cho phép bạn gán một giá trị cho nhiều biến cùng một lúc: x = y = z = 0tương đương x = (y = (z = 0))và có cùng tác dụng với các câu lệnh x = 0; y = 0; z = 0;.

Phiên bản tiếp theo của ngôn ngữ, C # 9.0, có thể có vào tháng 11 năm 2020, sẽ cho phép các thuộc tính chỉ đọc (hoặc tốt hơn là khởi tạo một lần) mà bạn có thể khởi tạo trong trình khởi tạo đối tượng. Điều này hiện không thể thực hiện được với các thuộc tính chỉ dành cho người nhận.

public string Name { get; init; }

var c = new C { Name = "c-sharp" };

2
Câu trả lời tuyệt vời, cảm ơn. Đối với thao tác db, nó sẽ giống như sau: IQueryable<T> result = db.Set<T>().Find(//just id here//).ToList();Nó sẽ biết rằng bạn đang tìm kiếm khóa chính. Chỉ để biết thêm thông tin thôi.
Mr. Blond

Tôi biết đây là một câu trả lời cũ, nhưng tôi sẽ tách get và set thành các phương thức khác nhau để giá trị không vô tình được đặt trong khi so sánh.
Joel Trauger

@JoelTrauger: Một so sánh đọc thuộc tính và do đó chỉ gọi getter.
Olivier Jacot-Descombes

Điều này đúng, nhưng một nhiệm vụ ngẫu nhiên sẽ gọi trình thiết lập và sửa đổi thuộc tính. Xem return object.property = valuevsreturn object.property == value
Joel Trauger 13/10/16

Một lệnh gọi ngẫu nhiên của một phương thức tập hợp riêng biệt cũng sẽ sửa đổi thuộc tính. Tôi không thấy các phương pháp get set riêng biệt có thể cải thiện độ an toàn như thế nào.
Olivier Jacot-Descombes

19
var list = new List<MyClass>();
var item = list.Find( x => x.GetId() == "TARGET_ID" );

hoặc nếu chỉ có một cái và bạn muốn thực thi một cái gì đó giống như SingleOrDefaultcái bạn muốn

var item = list.SingleOrDefault( x => x.GetId() == "TARGET" );

if ( item == null )
    throw new Exception();

Tại sao bạn sẽ sử dụng singleOrDefault nếu bạn muốn ném ngoại lệ, sử dụng đơn ()
Code Name Jack


6

Hoặc nếu bạn không thích sử dụng LINQ, bạn có thể làm theo cách cũ:

List<MyClass> list = new List<MyClass>();
foreach (MyClass element in list)
{
    if (element.GetId() == "heres_where_you_put_what_you_are_looking_for")
    {

        break; // If you only want to find the first instance a break here would be best for your application
    }
}

4

Bạn cũng có thể sử dụng phần mở rộng LINQ :

string id = "hello";
MyClass result = list.Where(m => m.GetId() == id).First();

4
hoặc quá tải khác của First:MyClass result = list.First(m => m.GetId() == id);
Marcel Gosselin

3

Bạn có thể giải quyết vấn đề của mình một cách ngắn gọn nhất với một vị từ được viết bằng cú pháp phương thức ẩn danh:

MyClass found = list.Find(item => item.GetID() == ID);

0
public List<DealsCategory> DealCategory { get; set; }
int categoryid = Convert.ToInt16(dealsModel.DealCategory.Select(x => x.Id));

Mặc dù mã này có thể trả lời câu hỏi, nhưng tốt hơn là giải thích cách giải quyết vấn đề và cung cấp mã làm ví dụ hoặc tài liệu tham khảo. Câu trả lời chỉ có mã có thể khó hiểu và thiếu ngữ cảnh.
Robert Columbia

0

Bạn có thể tạo một biến tìm kiếm để giữ các tiêu chí tìm kiếm của mình. Đây là một ví dụ sử dụng cơ sở dữ liệu.

 var query = from o in this.mJDBDataset.Products 
             where o.ProductStatus == textBox1.Text || o.Karrot == textBox1.Text 
             || o.ProductDetails == textBox1.Text || o.DepositDate == textBox1.Text 
             || o.SellDate == textBox1.Text
             select o;

 dataGridView1.DataSource = query.ToList();

 //Search and Calculate
 search = textBox1.Text;
 cnn.Open();
 string query1 = string.Format("select * from Products where ProductStatus='"
               + search +"'");
 SqlDataAdapter da = new SqlDataAdapter(query1, cnn);
 DataSet ds = new DataSet();
 da.Fill(ds, "Products");
 SqlDataReader reader;
 reader = new SqlCommand(query1, cnn).ExecuteReader();

 List<double> DuePayment = new List<double>();

 if (reader.HasRows)
 {

  while (reader.Read())
  {

   foreach (DataRow row in ds.Tables["Products"].Rows)
   {

     DuePaymentstring.Add(row["DuePayment"].ToString());
     DuePayment = DuePaymentstring.Select(x => double.Parse(x)).ToList();

   }
  }

  tdp = 0;
  tdp = DuePayment.Sum();                        
  DuePaymentstring.Remove(Convert.ToString(DuePaymentstring.Count));
  DuePayment.Clear();
 }
 cnn.Close();
 label3.Text = Convert.ToString(tdp + " Due Payment Count: " + 
 DuePayment.Count + " Due Payment string Count: " + DuePaymentstring.Count);
 tdp = 0;
 //DuePaymentstring.RemoveRange(0,DuePaymentstring.Count);
 //DuePayment.RemoveRange(0, DuePayment.Count);
 //Search and Calculate

Ở đây "truy vấn var" đang tạo các tiêu chí tìm kiếm mà bạn đang đưa ra thông qua biến tìm kiếm. Sau đó, "DuePaymentstring.Select" đang chọn dữ liệu phù hợp với tiêu chí đã cho của bạn. Hãy hỏi nếu bạn có vấn đề trong sự hiểu biết.

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.