Jak mogę znaleźć określony element w List <T>?

114

Moja aplikacja korzysta z takiej listy:

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

Za pomocą tej Addmetody MyClassdo listy dodawane jest kolejne wystąpienie .

MyClass udostępnia między innymi następujące metody:

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

Jak mogę znaleźć konkretną instancję MyClassza pomocą GetIdmetody? Wiem, że jest Findmetoda, ale nie wiem, czy to zadziała ?!

Robert Strauch
źródło

Odpowiedzi:

263

Użyj wyrażenia lambda

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

Uwaga: język C # ma wbudowaną składnię właściwości. Zamiast pisać metody pobierające i ustawiające (do czego przyzwyczaiłeś się w Javie), napisz

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

valuejest kontekstowym słowem kluczowym znanym tylko z metody dostępu set. Reprezentuje wartość przypisaną do właściwości.

Ponieważ ten wzorzec jest często używany, C # zapewnia właściwości implementowane automatycznie . Są krótką wersją powyższego kodu; jednak zmienna zapasowa jest ukryta i niedostępna (jest jednak dostępna z poziomu klasy w VB).

public string Id { get; set; }

Możesz po prostu użyć właściwości tak, jakbyś uzyskiwał dostęp do pola:

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

Korzystając z właściwości, można wyszukiwać elementy na liście w ten sposób

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

Jeśli potrzebujesz właściwości tylko do odczytu, możesz również użyć właściwości zaimplementowanych automatycznie:

public string Id { get; private set; }

Umożliwia to ustawienie Idwewnątrz klasy, ale nie z zewnątrz. Jeśli chcesz ustawić ją również w klasach pochodnych, możesz również chronić metodę ustawiającą

public string Id { get; protected set; }

I wreszcie, możesz zadeklarować właściwości jako virtuali przesłonić je w klasach pochodnych, co pozwoli ci zapewnić różne implementacje dla metod pobierających i ustawiających; tak jak w przypadku zwykłych metod wirtualnych.


Od C # 6,0 (Visual Studio 2015, Roslyn) można pisać właściwości automatyczne tylko do pobierania za pomocą inicjatora wbudowanego

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

Zamiast tego można również zainicjować właściwości tylko pobierające w konstruktorze. Getter tylko auto-właściwości są prawdziwymi właściwości tylko do odczytu, w przeciwieństwie do auto-wdrożone właściwości z prywatnym seter.

Działa to również z właściwościami automatycznymi do odczytu i zapisu:

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

Począwszy od języka C # 6,0 można również zapisywać właściwości jako elementy członkowskie zawierające wyrażenia

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

Zobacz: Platforma kompilatora .NET („Roslyn”)
         Nowe funkcje językowe w C # 6

Począwszy od języka C # 7.0 , zarówno getter, jak i setter, można zapisać za pomocą treści wyrażeń:

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

Zauważ, że w tym przypadku ustawiacz musi być wyrażeniem. To nie może być stwierdzenie. Powyższy przykład działa, ponieważ w C # przypisanie może być używane jako wyrażenie lub jako instrukcja. Wartość wyrażenia przypisania to przypisana wartość, w przypadku której samo przypisanie jest efektem ubocznym. Pozwala to na przypisanie wartości do więcej niż jednej zmiennej naraz: x = y = z = 0jest równoważne x = (y = (z = 0))i ma taki sam efekt jak instrukcje x = 0; y = 0; z = 0;.

Następna wersja języka, C # 9.0, prawdopodobnie dostępna w listopadzie 2020 r., Pozwoli na właściwości tylko do odczytu (lub lepiej zainicjuj raz), które można zainicjować w inicjatorze obiektu. Obecnie nie jest to możliwe w przypadku właściwości tylko pobierających.

public string Name { get; init; }

var c = new C { Name = "c-sharp" };
Olivier Jacot-Descombes
źródło
2
Świetna odpowiedź, dzięki. W przypadku operacji db wyglądałoby to mniej więcej tak: IQueryable<T> result = db.Set<T>().Find(//just id here//).ToList();wiedziałoby już, że szukasz klucza podstawowego. Tylko dla informacji.
Mr. Blond
Wiem, że to stara odpowiedź, ale oddzieliłbym get i ustawił na różne metody, aby wartość nie została przypadkowo ustawiona podczas porównania.
Joel Trauger
@JoelTrauger: Porównanie odczytuje właściwość i dlatego wywołuje tylko metodę pobierającą.
Olivier Jacot-Descombes
To prawda, ale przypadkowe przypisanie wywoła ustawiającego i zmodyfikuje właściwość. Zobacz return object.property = valuevsreturn object.property == value
Joel Trauger
Przypadkowe wywołanie oddzielnej metody set również zmodyfikuje właściwość. Nie widzę, jak oddzielne metody get set mogą poprawić bezpieczeństwo.
Olivier Jacot-Descombes
19
var list = new List<MyClass>();
var item = list.Find( x => x.GetId() == "TARGET_ID" );

lub jeśli jest tylko jeden i chcesz wymusić, że coś takiego SingleOrDefaultmoże być tym, czego chcesz

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

if ( item == null )
    throw new Exception();
zellio
źródło
Dlaczego użyjesz singleOrDefault, jeśli chcesz rzucić wyjątek, użyj Single ()
nazwa kodowa Jack
10

Próbować:

 list.Find(item => item.id==myid);
Amritpal Singh
źródło
6

Lub jeśli nie wolisz używać LINQ , możesz to zrobić w oldschoolowy sposób:

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
    }
}
Bjørn
źródło
4

Możesz także użyć rozszerzeń LINQ :

string id = "hello";
MyClass result = list.Where(m => m.GetId() == id).First();
Guffa
źródło
4
lub inne przeładowanie First:MyClass result = list.First(m => m.GetId() == id);
Marcel Gosselin
3

Możesz rozwiązać swój problem najbardziej zwięźle za pomocą predykatu napisanego przy użyciu składni metody anonimowej:

MyClass found = list.Find(item => item.GetID() == ID);
David Heffernan
źródło
0
public List<DealsCategory> DealCategory { get; set; }
int categoryid = Convert.ToInt16(dealsModel.DealCategory.Select(x => x.Id));
Muhammad Armaghan
źródło
Chociaż ten kod może odpowiedzieć na pytanie, lepiej jest wyjaśnić, jak rozwiązać problem i podać kod jako przykład lub odniesienie. Odpowiedzi zawierające tylko kod mogą być mylące i pozbawione kontekstu.
Robert Columbia
0

Możesz utworzyć zmienną wyszukiwania, aby przechowywać kryteria wyszukiwania. Oto przykład użycia bazy danych.

 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

Tutaj "var query" generuje kryteria wyszukiwania, które podajesz za pomocą zmiennej wyszukiwania. Następnie „DuePaymentstring.Select” wybiera dane pasujące do podanych kryteriów. Nie wahaj się zapytać, czy masz problem ze zrozumieniem.

Khandkar Asif Hossain
źródło