Как найти определенный элемент в List <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- контекстное ключевое слово, известное только в методе доступа set. Он представляет значение, присвоенное свойству.

Поскольку этот шаблон часто используется, 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и переопределять их в производных классах, что позволяет вам предоставлять различные реализации для геттеров и сеттеров; как и для обычных виртуальных методов.


Начиная с C # 6.0 (Visual Studio 2015, Roslyn) вы можете писать автоматические свойства только для получения с помощью встроенного инициализатора.

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

Вместо этого вы также можете инициализировать свойства только для получения в конструкторе. Автоматические свойства только для получения являются истинными свойствами, доступными только для чтения, в отличие от автоматически реализуемых свойств с частным установщиком.

Это также работает с автоматическими свойствами чтения-записи:

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 ("Roslyn")
          Новые языковые возможности в C # 6

Начиная с C # 7.0 , оба метода получения и установки могут быть написаны с телами выражений:

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: сравнение считывает свойство и, следовательно, вызывает только метод получения.
Оливье Жако-Декомб,
Это правда, но случайное присвоение вызовет установщик и изменит свойство. See return object.property = valuevsreturn object.property == value
Джоэл Траугер
Случайный вызов отдельного метода set также изменит свойство. Я не понимаю, как отдельные методы get set могут повысить безопасность.
Оливье Жако-Декомб,
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();
zellio
источник
Почему вы будете использовать singleOrDefault, если хотите генерировать исключение, используйте Single ()
кодовое имя Jack
10

Пытаться:

 list.Find(item => item.id==myid);
Амритпал Сингх
источник
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();
Guffa
источник
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» выбирает данные, соответствующие заданным вами критериям. Не стесняйтесь спрашивать, если у вас проблемы с пониманием.

Хандкар Асиф Хоссейн
источник