Benutzer mit den meisten Antworten
Wie erstelle ich ein IEnumerator?

Frage
-
Hallo Community,
ich habe folgenden Fehler:
Schweregrad Code Beschreibung Projekt Datei Zeile Unterdrückungszustand Fehler CS1579 Eine foreach-Anweisung kann nicht für Variablen vom Typ "TeamSpeak3QueryApi.Net.Program.Structs.BotConnections" verwendet werden, da "TeamSpeak3QueryApi.Net.Program.Structs.BotConnections" keine öffentliche Definition für "GetEnumerator" enthält. TeamSpeak3QueryApi.Program C:\Users\lgund\Downloads\C-Querybot-master\C-Querybot-master\TeamSpeak3QueryApi.Program\Program.cs 103 Aktiv
Ich bin allerdings hoffnungslos überforder, wie ich bei BotConnections so ein IEnumerator hinzufügen kann. Ich hoffe ihr könnt mir da weiter helfen...
Meine BotConnections:
using System.Collections.Generic; using TeamSpeak3QueryApi.Net.Specialized; namespace TeamSpeak3QueryApi.Net.Program.Structs { class BotConnections { public int id { get; set; } public int instance { get; set; } public List<SidInfo> sids { get; set; } public class SidInfo { public bool isActive { get; set; } public int lastSeen { get; set; } public int id { get; set; } public string botname { get; set; } public bool isWelcomeMessage { get; set; } public string welcomeMessage { get; set; } public bool isAfkMove { get; set; } public int afkMoveChannel { get; set; } public TeamSpeakClient teamspeak { get; set; } } } }
Antworten
-
Hallo,
das Ganze sieht nach dem ersten Szenario aus, das ich beschrieben hatte.
Erstelle in der Klasse, die die BotConnections verwaltet eine List<BotConnection> (s bei Klasse streichen):
private List<BotConnection> BotConnections = new List<BotConnection>();
Damit gibt es den Enumerator frei Haus und Du kannst damit die einzelnen Verbindungsinstanzen verwalten (Add, Remove usw.), genauso wie Du es bereits mit der SidInfo Liste tust.
Zum restlichen Code: Es ist vergleichsweise ineffizient für jede einzelne SidInfo eine neue Abfrage zu starten. Dabei ist i. a. der Overhead für das Erstellen und Ausführen der Abfrage und das Übertragen der Daten (vor allem in Netzwerk) höher, als wenn man alles auf einen Rutsch abfragt.
Da der Aufbau vermuten lässt, dass die SidInfo mit der BotConnection zusammenhängen und die abhängigen Daten über die BotConnection.Id bzw. BotConnection.Instance identizifiert werden können, verwende sie als Abfragekriterien, so dass alle verwendeten Daten (keine *) geliefert werden.
Derzeit hast Du einen Cross Join in deiner Abfrage, d. h. gibt es mehr als eine Zeile, so werden gleiche Daten etliche Male abgerufen. Gibt es Beziehungen bei den Tabellen zueinander verwende einen INNER/LEFT JOIN, oder führe die einzelnen Abfrage in einem Stapel ab. Bei letzterem hat der Reader mehrere Ergebnis (NextResult).
Angedeutet der Code dazu:
// TODO: * vermeiden, nur verwendete Daten abrufen // TODO: Verwenden von INNER JOIN oder mehreren Abfragen (derzeit CROSS JOIN) command.CommandText = "SELECT con.id, con.botname, pat.*, afk.*, messages.* " + "FROM bot_connections con, bot_bad_pattern pat, bot_settigns_afk afk, bot_settings_messages messages " + "WHERE con.id=@botid AND pat.id=@botid AND afk.id=@botid AND messages.id=@botid;"; command.Parameters.Clear(); SqlParameter botid = command.Parameters.Add("@botid", SqlDbType.Int); // SQL Server angenommen, andere entsprechend foreach (BotConnection Bot in BotConnections) // siehe oben { foreach (BotConnections.SidInfo Server in Bot) { botid = Bot.id // lokale Variable reicht using (var reader = command.ExecuteReader()) // impliziert Dispose (auch bei Exception) { while(reader.Read()) { // sinnvolles damit anfangen } } } }
Gruß Elmar- Als Antwort vorgeschlagen Dimitar DenkovMicrosoft contingent staff, Administrator Montag, 22. Mai 2017 06:49
- Als Antwort markiert Dimitar DenkovMicrosoft contingent staff, Administrator Mittwoch, 31. Mai 2017 12:59
Alle Antworten
-
Hi,
poste bitte mal deinen Code, der den Fehler verursacht.
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community -
Hallo First-Coder,
Du implementierst die IEnumerator Schnittstelle am besten so wie in der MSDN beschrieben und mit Beispiel gezeigt: IEnumerator<T>-Schnittstelle
Sollte das nicht helfen, konkretisiere deine Frage bitte.
- Gruß Florian
-
Hallo,
deine Klasse BotConnections ist keine Auflistung (Array, Collection, List). Nur diese haben von Haus einen Enumerator, da sie dafür bestimmt sind mehrere gleichartige Instanzen aufzunehmen.
Wenn Du dem Namen nach mehrere "BotConnection" Instanzen verwenden willst, so verwende eine List<BotConnection> und erstelle sie als Instanz in der verwaltenden Klasse. Auf das irreführende Plural-"S" solltest Du in dem Fall verzichten.
Oder aber leite "BotConnection(s)" von List<T> oder einer anderen Auflistung ab. Wobei das, nach den verwendeten Eigenschaften (ID, Instance) zu urteilen, vermutlich nicht Deine Absicht sein wird.
Gruß Elmar
-
Den meisten Quelltext habt ihr ja schon, der Aufruf mit der foreach sieht so aus:
foreach (BotConnections Bot in BotConnections) { foreach (BotConnections.SidInfo Server in Bot) { command.CommandText = "SELECT con.id, con.botname, pat.*, afk.*, messages.* FROM bot_connections con, bot_bad_pattern pat, bot_settigns_afk afk, bot_settings_messages messages WHERE con.id =" + Bot.id + " AND pat.id =" + Bot.id + " AND afk.id =" + Bot.id + " AND messages.id =" + Bot.id; Reader = command.ExecuteReader(); while (Reader.Read()) { for (int i = 0; i < Reader.FieldCount; i++) { Log.Write(Log.Level.Debug, Bot.id + ": Found " + Reader.GetName(i).ToString() + " Value: " + Reader.GetString(i).ToString()); } } command.Dispose(); Reader.Dispose(); } }
Die Instanz hat mehrere serverids (sids), die ich mit einer extra foreach abfragen wollte. Leider bin ich noch neu in der Sprache, ich hoffe ihr nimmt es nicht übel.
-
Hallo,
das Ganze sieht nach dem ersten Szenario aus, das ich beschrieben hatte.
Erstelle in der Klasse, die die BotConnections verwaltet eine List<BotConnection> (s bei Klasse streichen):
private List<BotConnection> BotConnections = new List<BotConnection>();
Damit gibt es den Enumerator frei Haus und Du kannst damit die einzelnen Verbindungsinstanzen verwalten (Add, Remove usw.), genauso wie Du es bereits mit der SidInfo Liste tust.
Zum restlichen Code: Es ist vergleichsweise ineffizient für jede einzelne SidInfo eine neue Abfrage zu starten. Dabei ist i. a. der Overhead für das Erstellen und Ausführen der Abfrage und das Übertragen der Daten (vor allem in Netzwerk) höher, als wenn man alles auf einen Rutsch abfragt.
Da der Aufbau vermuten lässt, dass die SidInfo mit der BotConnection zusammenhängen und die abhängigen Daten über die BotConnection.Id bzw. BotConnection.Instance identizifiert werden können, verwende sie als Abfragekriterien, so dass alle verwendeten Daten (keine *) geliefert werden.
Derzeit hast Du einen Cross Join in deiner Abfrage, d. h. gibt es mehr als eine Zeile, so werden gleiche Daten etliche Male abgerufen. Gibt es Beziehungen bei den Tabellen zueinander verwende einen INNER/LEFT JOIN, oder führe die einzelnen Abfrage in einem Stapel ab. Bei letzterem hat der Reader mehrere Ergebnis (NextResult).
Angedeutet der Code dazu:
// TODO: * vermeiden, nur verwendete Daten abrufen // TODO: Verwenden von INNER JOIN oder mehreren Abfragen (derzeit CROSS JOIN) command.CommandText = "SELECT con.id, con.botname, pat.*, afk.*, messages.* " + "FROM bot_connections con, bot_bad_pattern pat, bot_settigns_afk afk, bot_settings_messages messages " + "WHERE con.id=@botid AND pat.id=@botid AND afk.id=@botid AND messages.id=@botid;"; command.Parameters.Clear(); SqlParameter botid = command.Parameters.Add("@botid", SqlDbType.Int); // SQL Server angenommen, andere entsprechend foreach (BotConnection Bot in BotConnections) // siehe oben { foreach (BotConnections.SidInfo Server in Bot) { botid = Bot.id // lokale Variable reicht using (var reader = command.ExecuteReader()) // impliziert Dispose (auch bei Exception) { while(reader.Read()) { // sinnvolles damit anfangen } } } }
Gruß Elmar- Als Antwort vorgeschlagen Dimitar DenkovMicrosoft contingent staff, Administrator Montag, 22. Mai 2017 06:49
- Als Antwort markiert Dimitar DenkovMicrosoft contingent staff, Administrator Mittwoch, 31. Mai 2017 12:59