Як я можу знайти певний елемент у списку <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 # має вбудований синтаксис властивостей. Замість того, щоб писати геттер і методи сеттера (як ви могли звикати з Java), пишіть

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

value- це контекстне ключове слово, відоме лише у встановленому аксесуарі. Він представляє значення, присвоєне властивості.

Оскільки ця модель часто використовується, 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) ви можете записувати автоматичні властивості лише для отримання з допомогою вбудованого ініціалізатора

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

Натомість можна також ініціалізувати властивості лише для getter у конструкторі. Автоматичні властивості лише для 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 ("Рослін")
         Нові мовні функції в C # 6

Починаючи з C # 7.0 , і getter, і seter, можна записати з виразними телами:

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

Зауважте, що в цьому випадку сеттер повинен бути виразом. Це не може бути твердженням. Наведений вище приклад працює, тому що в C # призначення може використовуватися як вираз або як вислів. Значення виразу присвоєння - це присвоєне значення, коли саме призначення є побічним ефектом. Це дозволяє призначити значення більш ніж одній змінній одночасно: x = y = z = 0еквівалентно x = (y = (z = 0))та має такий же ефект, як і заяви x = 0; y = 0; z = 0;.

Наступна версія мови, C # 9.0, ймовірно, доступна в листопаді 2020 року, дозволить властивості лише для читання (або краще ініціалізувати один раз), які можна ініціалізувати в ініціалізаторі об'єктів. Наразі це неможливо із властивостями лише для отримання.

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();вже знали б, що ви шукаєте первинний ключ. Просто для інформації.
Містер Блонд

Я знаю, що це стара відповідь, але я розділяю get і set на різні методи, щоб значення випадково не було встановлено під час порівняння.
Джоель Траугер

@JoelTrauger: Порівняння зчитує властивість і тому викликає лише геттера.
Олів'є Якот-Дескомбс

Це правда, але випадкове призначення зателефонує сеттеру та змінить властивість. Дивіться return object.property = valueпротиreturn object.property == value
Джоель Траугер

Випадковий виклик окремого методу набору також змінить властивість. Я не бачу, як окремі методи набору можуть підвищити безпеку.
Олів'є Якот-Дескомб

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 ()
ім'я коду Jack 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
або інше перевантаження Першого:MyClass result = list.First(m => m.GetId() == id);
Марсель Госселін

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

Хоча цей код може відповісти на питання, краще пояснити, як вирішити проблему, та надати код як приклад чи посилання. Відповіді, що стосуються лише коду, можуть бути заплутаними та відсутністю контексту.
Роберт Колумбія

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" вибирає дані, що відповідають вашим заданим критеріям. Сміливо запитайте, чи маєте ви розуміння проблем.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.