Wie finde ich ein bestimmtes Element in einer Liste <T>?

114

Meine Anwendung verwendet eine Liste wie folgt:

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

Mit der AddMethode MyClasswird der Liste eine weitere Instanz von hinzugefügt.

MyClass bietet unter anderem folgende Methoden:

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

Wie kann ich MyClassmithilfe der GetIdMethode eine bestimmte Instanz von finden ? Ich weiß, dass es die FindMethode gibt, aber ich weiß nicht, ob das hier funktionieren würde?!

Robert Strauch
quelle

Antworten:

262

Verwenden Sie einen Lambda-Ausdruck

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

Hinweis: C # verfügt über eine integrierte Syntax für Eigenschaften. Anstatt Getter- und Setter-Methoden zu schreiben (wie Sie es von Java gewohnt sind), schreiben Sie

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

valueist ein kontextbezogenes Schlüsselwort, das nur im Set-Accessor bekannt ist. Es repräsentiert den der Eigenschaft zugewiesenen Wert.

Da dieses Muster häufig verwendet wird, bietet C # automatisch implementierte Eigenschaften . Sie sind eine Kurzversion des obigen Codes; Die Hintergrundvariable ist jedoch ausgeblendet und nicht zugänglich (sie ist jedoch innerhalb der Klasse in VB zugänglich).

public string Id { get; set; }

Sie können Eigenschaften einfach so verwenden, als würden Sie auf ein Feld zugreifen:

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

Mithilfe von Eigenschaften würden Sie nach Elementen in der Liste wie folgt suchen

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

Sie können auch automatisch implementierte Eigenschaften verwenden, wenn Sie eine schreibgeschützte Eigenschaft benötigen:

public string Id { get; private set; }

Auf diese Weise können Sie die Idinnerhalb der Klasse festlegen, jedoch nicht von außen. Wenn Sie es auch in abgeleiteten Klassen festlegen müssen, können Sie den Setter auch schützen

public string Id { get; protected set; }

Und schließlich können Sie Eigenschaften als deklarieren virtualund sie beim Ableiten von Klassen überschreiben, sodass Sie verschiedene Implementierungen für Getter und Setter bereitstellen können. genau wie bei gewöhnlichen virtuellen Methoden.


Seit C # 6.0 (Visual Studio 2015, Roslyn) können Sie mit einem Inline-Initialisierer nur Getter-Auto-Eigenschaften schreiben

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

Sie können stattdessen auch Nur-Getter-Eigenschaften im Konstruktor initialisieren. Nur-Getter-Auto-Eigenschaften sind echte schreibgeschützte Eigenschaften, im Gegensatz zu automatisch implementierten Eigenschaften mit einem privaten Setter.

Dies funktioniert auch mit automatischen Lese- / Schreib-Eigenschaften:

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

Ab C # 6.0 können Sie Eigenschaften auch als Ausdruckskörper schreiben

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

Siehe: .NET Compiler Platform ("Roslyn")
         Neue Sprachfunktionen in C # 6

Ab C # 7.0 können sowohl Getter als auch Setter mit Ausdruckskörpern geschrieben werden:

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

Beachten Sie, dass in diesem Fall der Setter ein Ausdruck sein muss. Es kann keine Aussage sein. Das obige Beispiel funktioniert, da in C # eine Zuweisung als Ausdruck oder als Anweisung verwendet werden kann. Der Wert eines Zuweisungsausdrucks ist der zugewiesene Wert, bei dem die Zuweisung selbst ein Nebeneffekt ist. Auf diese Weise können Sie mehreren Variablen gleichzeitig einen Wert zuweisen: x = y = z = 0Entspricht x = (y = (z = 0))den Anweisungen und hat dieselbe Wirkung wie diese x = 0; y = 0; z = 0;.

Die nächste Version der Sprache, C # 9.0, die voraussichtlich im November 2020 verfügbar sein wird, ermöglicht schreibgeschützte (oder besser einmalige) Eigenschaften, die Sie in einem Objektinitialisierer initialisieren können. Dies ist derzeit mit Nur-Getter-Eigenschaften nicht möglich.

public string Name { get; init; }

var c = new C { Name = "c-sharp" };
Olivier Jacot-Descombes
quelle
2
Tolle Antwort, danke. Für den DB-Betrieb würde es ungefähr so ​​aussehen: IQueryable<T> result = db.Set<T>().Find(//just id here//).ToList();Es würde bereits wissen, dass Sie nach einem Primärschlüssel suchen. Nur zur Info.
Mr. Blond
Ich weiß, dass dies eine alte Antwort ist, aber ich würde get und set in verschiedene Methoden unterteilen, damit der Wert während eines Vergleichs nicht versehentlich festgelegt wird.
Joel Trauger
@JoelTrauger: Ein Vergleich liest die Eigenschaft und ruft daher nur den Getter auf.
Olivier Jacot-Descombes
Dies ist wahr, aber eine versehentliche Zuweisung ruft den Setter auf und ändert die Eigenschaft. Siehe return object.property = valuevsreturn object.property == value
Joel Trauger
Ein versehentlicher Aufruf einer separaten Set-Methode ändert ebenfalls die Eigenschaft. Ich sehe nicht, wie separate Get-Set-Methoden die Sicherheit verbessern können.
Olivier Jacot-Descombes
19
var list = new List<MyClass>();
var item = list.Find( x => x.GetId() == "TARGET_ID" );

oder wenn es nur einen gibt und Sie erzwingen möchten, dass so etwas wie das sein SingleOrDefaultkann, was Sie wollen

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

if ( item == null )
    throw new Exception();
zellio
quelle
Warum werden Sie singleOrDefault verwenden, wenn Sie eine Ausnahme auslösen möchten? Verwenden Sie Single ()
Codename Jack
10

Versuchen:

 list.Find(item => item.id==myid);
Amritpal Singh
quelle
6

Oder wenn Sie LINQ nicht bevorzugen, können Sie dies auf die alte Art tun:

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
quelle
4

Sie können auch LINQ- Erweiterungen verwenden:

string id = "hello";
MyClass result = list.Where(m => m.GetId() == id).First();
Guffa
quelle
4
oder die andere Überladung von First:MyClass result = list.First(m => m.GetId() == id);
Marcel Gosselin
3

Sie können Ihr Problem am präzisesten mit einem Prädikat lösen, das mit anonymer Methodensyntax geschrieben wurde:

MyClass found = list.Find(item => item.GetID() == ID);
David Heffernan
quelle
0
public List<DealsCategory> DealCategory { get; set; }
int categoryid = Convert.ToInt16(dealsModel.DealCategory.Select(x => x.Id));
Muhammad Armaghan
quelle
Während dieser Code die Frage beantworten kann, ist es besser zu erklären, wie das Problem gelöst werden kann, und den Code als Beispiel oder Referenz bereitzustellen. Nur-Code-Antworten können verwirrend sein und keinen Kontext haben.
Robert Columbia
0

Sie können eine Suchvariable erstellen, die Ihre Suchkriterien enthält. Hier ist ein Beispiel für die Verwendung einer Datenbank.

 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

Hier generiert "var query" die Suchkriterien, die Sie über die Suchvariable angeben. Dann wählt "DuePaymentstring.Select" die Daten aus, die Ihren angegebenen Kriterien entsprechen. Fühlen Sie sich frei zu fragen, ob Sie Probleme beim Verständnis haben.

Khandkar Asif Hossain
quelle