ฉันจะค้นหาองค์ประกอบเฉพาะในรายการ <T> ได้อย่างไร


114

แอปพลิเคชันของฉันใช้รายการดังนี้:

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

เมื่อใช้AddวิธีMyClassนี้จะเพิ่มอินสแตนซ์อื่นในรายการ

MyClass ให้วิธีการต่อไปนี้:

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

ฉันจะค้นหาอินสแตนซ์เฉพาะของMyClassการใช้GetIdวิธีนี้ได้อย่างไร ฉันรู้ว่ามีFindวิธีนี้ แต่ฉันไม่รู้ว่าจะใช้ได้หรือไม่!

คำตอบ:


263

ใช้นิพจน์แลมบ์ดา

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

หมายเหตุ: C # มีไวยากรณ์ในตัวสำหรับคุณสมบัติ แทนที่จะเขียนเมธอด getter และ setter (อย่างที่คุณคุ้นเคยจาก Java) ให้เขียน

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

valueเป็นคีย์เวิร์ดตามบริบทที่รู้จักเฉพาะใน set accessor แสดงถึงค่าที่กำหนดให้กับคุณสมบัติ

ตั้งแต่รูปแบบนี้มักจะใช้, C # ให้ คุณสมบัติอัตโนมัติดำเนินการ เป็นโค้ดสั้น ๆ ด้านบน อย่างไรก็ตามตัวแปรสำรองจะถูกซ่อนและไม่สามารถเข้าถึงได้ (สามารถเข้าถึงได้จากภายในคลาสใน VB อย่างไรก็ตาม)

public string Id { get; set; }

คุณสามารถใช้คุณสมบัติราวกับว่าคุณกำลังเข้าถึงฟิลด์:

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

เมื่อใช้คุณสมบัติคุณจะค้นหารายการในรายการเช่นนี้

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

คุณยังสามารถใช้คุณสมบัติที่ติดตั้งอัตโนมัติได้หากคุณต้องการคุณสมบัติแบบอ่านอย่างเดียว:

public string Id { get; private set; }

สิ่งนี้ช่วยให้คุณสามารถตั้งค่าIdภายในชั้นเรียน แต่ไม่ใช่จากภายนอก หากคุณต้องการตั้งค่าในคลาสที่ได้รับมาด้วยเช่นกันคุณสามารถป้องกันเซ็ตเตอร์ได้

public string Id { get; protected set; }

และสุดท้ายคุณสามารถประกาศคุณสมบัติเป็นvirtualและลบล้างคุณสมบัติเหล่านั้นในคลาสที่ได้มาซึ่งช่วยให้คุณสามารถจัดเตรียมการนำไปใช้งานที่แตกต่างกันสำหรับ getters และ setters เช่นเดียวกับวิธีการเสมือนทั่วไป


ตั้งแต่ C # 6.0 (Visual Studio 2015, Roslyn) คุณสามารถเขียนคุณสมบัติอัตโนมัติของ getter-only ด้วยตัวเริ่มต้นแบบอินไลน์

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

คุณยังสามารถเริ่มต้นคุณสมบัติ getter-only ภายในตัวสร้างแทนได้ คุณสมบัติอัตโนมัติของ Getter เท่านั้นเป็นคุณสมบัติแบบอ่านอย่างเดียวที่แท้จริงซึ่งแตกต่างจากคุณสมบัติที่ใช้งานอัตโนมัติด้วยตัวตั้งค่าส่วนตัว

สิ่งนี้ใช้ได้กับคุณสมบัติอัตโนมัติแบบอ่าน - เขียน:

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

เริ่มต้นด้วย C # 6.0 คุณยังสามารถเขียนคุณสมบัติเป็นสมาชิกที่มีนิพจน์ได้

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

ดู: .NET Compiler Platform ("Roslyn")
         คุณลักษณะภาษาใหม่ใน C # 6

เริ่มต้นด้วยC # 7.0ทั้ง getter และ setter สามารถเขียนด้วย expression body:

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

โปรดทราบว่าในกรณีนี้ setter ต้องเป็นนิพจน์ มันไม่สามารถเป็นคำสั่ง ตัวอย่างข้างต้นใช้งานได้เนื่องจากใน C # งานสามารถใช้เป็นนิพจน์หรือเป็นคำสั่งได้ ค่าของนิพจน์การกำหนดคือค่าที่กำหนดโดยที่การกำหนดเองเป็นผลข้างเคียง นี้จะช่วยให้คุณสามารถกำหนดค่าให้กับตัวแปรมากกว่าหนึ่งในครั้งเดียว: x = y = z = 0เทียบเท่ากับและมีผลเช่นเดียวกับงบx = (y = (z = 0))x = 0; y = 0; z = 0;

เวอร์ชันถัดไปของภาษา C # 9.0 ซึ่งอาจพร้อมใช้งานในเดือนพฤศจิกายน 2020 จะอนุญาตคุณสมบัติอ่านอย่างเดียว (หรือดีกว่าเริ่มต้นครั้งเดียว) ที่คุณสามารถเริ่มต้นในตัวเริ่มต้นอ็อบเจ็กต์ ขณะนี้ไม่สามารถทำได้ด้วยคุณสมบัติ getter-only

public string Name { get; init; }

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

2
คำตอบที่ดีขอบคุณ สำหรับการทำงานของ db จะมีลักษณะดังนี้: IQueryable<T> result = db.Set<T>().Find(//just id here//).ToList();มันจะรู้อยู่แล้วว่าคุณกำลังมองหาคีย์หลัก สำหรับข้อมูล
Mr. Blond

ฉันรู้ว่านี่เป็นคำตอบเก่า แต่ฉันจะแยก get และ set เป็นวิธีการต่างๆเพื่อไม่ให้ตั้งค่าโดยไม่ได้ตั้งใจระหว่างการเปรียบเทียบ
Joel Trauger

@JoelTrauger: การเปรียบเทียบอ่านคุณสมบัติดังนั้นจึงเรียกเฉพาะ getter
Olivier Jacot-Descombes

นี่เป็นความจริง แต่การมอบหมายโดยไม่ได้ตั้งใจจะเรียกผู้ตั้งค่าและแก้ไขคุณสมบัติ ดูreturn object.property = valuevsreturn object.property == value
Joel Trauger

การเรียกชุดวิธีแยกโดยไม่ได้ตั้งใจจะแก้ไขคุณสมบัติด้วยเช่นกัน ฉันไม่เห็นว่าวิธีการตั้งค่าแยกต่างหากจะช่วยเพิ่มความปลอดภัยได้อย่างไร
Olivier Jacot-Descombes

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

หรือหากมีเพียงหนึ่งเดียวและคุณต้องการบังคับใช้สิ่งSingleOrDefaultนั้นอาจเป็นสิ่งที่คุณต้องการ

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

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

ทำไมคุณถึงใช้ singleOrDefault ถ้าคุณต้องการโยนข้อยกเว้น Use Single ()
Code Name Jack


6

หรือหากคุณไม่ต้องการใช้LINQคุณสามารถทำได้ด้วยวิธีแบบเก่า:

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

คุณยังสามารถใช้ส่วนขยายLINQ :

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

4
หรือเกินพิกัดอื่น ๆ ของ First:MyClass result = list.First(m => m.GetId() == id);
Marcel Gosselin

3

คุณสามารถแก้ปัญหาของคุณได้อย่างรัดกุมที่สุดด้วยเพรดิเคตที่เขียนโดยใช้ไวยากรณ์วิธีการไม่ระบุชื่อ:

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

แม้ว่ารหัสนี้อาจตอบคำถามได้ แต่ก็ควรอธิบายวิธีแก้ปัญหาและระบุรหัสเป็นตัวอย่างหรือข้อมูลอ้างอิงได้ดีกว่า คำตอบแบบใช้รหัสเท่านั้นอาจทำให้สับสนและขาดบริบท
Robert Columbia

0

คุณสามารถสร้างตัวแปรการค้นหาเพื่อเก็บเกณฑ์การค้นหาของคุณ นี่คือตัวอย่างการใช้ฐานข้อมูล

 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

ที่นี่ "var query" กำลังสร้างเกณฑ์การค้นหาที่คุณระบุผ่านตัวแปรการค้นหา จากนั้น "DuePaymentstring.Select" คือการเลือกข้อมูลที่ตรงกับเกณฑ์ที่คุณกำหนด อย่าลังเลที่จะถามหากคุณมีปัญหาในการทำความเข้าใจ

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