Question Getting error about needing GetEnumerator, but I'm using foreach

David_Ford

Member
Joined
Apr 23, 2017
Messages
12
Programming Experience
10+
Hi. Trying to teach myself some Blazor coding, and I'm having a generally rough time, with some success here and there. I could really use a hand here.

I wrote one app that was able to talk to the AdventureWorks db, and spit back some addresses on the screen. I used the "foreach" method to loop through.

I'm trying it with another app now, and though I thought I modelled the code off the original, something is wrong. I'm getting a couple of errors I didn't get before:

Severity Code Description Project File Line Suppression State
Error (active) CS1579 foreach statement cannot operate on variables of type 'DataAccessService' because 'DataAccessService' does not contain a public instance or extension definition for 'GetEnumerator' BlazorServerApp C:\Users\DSNoS\source\repos\BlazorServerApp\BlazorServerApp\Pages\FetchData.razor 30

Severity Code Description Project File Line Suppression State
Error (active) CS0120 An object reference is required for the non-static field, method, or property 'DataAccessService.GetPersonList()' BlazorServerApp C:\Users\DSNoS\source\repos\BlazorServerApp\BlazorServerApp\Pages\FetchData.razor 47

Here is the code to my class module. I tried adding GetEnumerator, but evidently either I didn't do it right (likely), or something else is wrong and I'm getting a bogus error message.

C#:
using Microsoft.Extensions.Configuration;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Threading.Tasks;

namespace BlazorServerApp.Data
{
    public class DataAccessService
    {
        private readonly IConfiguration config;
        public DataAccessService(IConfiguration configuration)
        {
            config = configuration;
        }

        private string ConnectionString
        {
            get
            {
                string _server = config.GetValue<string>("DbConfig:ServerName");
                string _database = config.GetValue<string>("DbConfig:DatabaseName");
                //string _username = config.GetValue<string>("DbConfig:UserName");
                //string _password = config.GetValue<string>("DbConfig:password");
                //return ($"Server={_server};Database={_database};User ID={_username};Password={_password};Trusted_Connection=true;MultipleActiveResultSets=true;");
                return ($"Server={_server};Database={_database};Trusted_Connection=true;MultipleActiveResultSets=true;");
            }
        }

      /*  IEnumerator IEnumerable.GetEnumerator()
        {

            return (IEnumerator) GetEnumerator();
        }

        public PeopleEnum GetEnumerator()
        {
            return new PeopleEnum(_people);
        }
   
        public interface IEnumerator
        {
            bool MoveNext();
            object Current { get; }
            void Reset();
        }

        public interface IEnumerable
        {
            IEnumerator GetEnumerator();
        }
      */
        public async Task<List<Person>> GetPersonList()
        {
            List<Person> people = new List<Person>();
            Person p;
         
            DataTable dt = new DataTable();
            SqlConnection con = new SqlConnection(ConnectionString);
            SqlDataAdapter da = new SqlDataAdapter("SELECT a.[BusinessEntityID],a.[FirstName] ,a.[MiddleName] ,a.[LastName] ,a.[Suffix], a.StateProvinceID, a.[ModifiedDate] , " +
                "d.addressline1, d.addressline2, d.city, d.postalcode, d.AddressID, ,d.StateProvinceID , e.[StateProvinceCode], e.[CountryRegionCode]" +
                " FROM[AdventureWorks2019].[Person].[Person]  a  inner join AdventureWorks2019.Person.BusinessEntityAddress c on" +
                "  a.BusinessEntityID = c.BusinessEntityID  inner join AdventureWorks2019.person.Address d on c.addressid = d.addressid" +
                "inner join AdventureWorks2019.person.StateProvince e on  d.stateprovinceid = e.StateProvinceID", con);
            da.Fill(dt);
            foreach (DataRow row in dt.Rows)
            {
                p = new Person();
                p.BusinessEntityID = Convert.ToInt32(row["BusinessEntityID"]);
                p.FirstName = row["FirstName"].ToString();
                p.Middle = row["Middle"].ToString();
                p.LastName = row["LastName"].ToString();
                p.Suffix = row["Suffix"].ToString();
                p.StateProvinceID = Convert.ToInt32(row["StateProvinceID"]);
                p.AddressID = Convert.ToInt32(row["AddressId"]);
                p.AddressLine1 = row["AddressLine1"].ToString();
                p.AddressLine2 = row["AddressLine2"].ToString();
                p.City = row["City"].ToString();
                p.StateProvinceID = Convert.ToInt32(row["StateProvinceID"]);
                p.StateProvinceCode = row["StateProvinceCode"].ToString();
                p.CountryRegionCode = row["CountryRegionCode"].ToString();
                people.Add(p);
            }
            con.Close();  
            return await Task.FromResult(people);
         

        }
     
    }

    public class Person
    {
        public int BusinessEntityID { get; set; }
        public string? FirstName { get; set; }
        public string? Middle { get; set; }
        public string? LastName { get; set; }
        public string? Suffix { get; set; }
        public int AddressID { get; set; }
        public string? AddressLine1 { get; set; }
        public string? AddressLine2 { get; set; }
        public string? City { get; set; }
        public int StateProvinceID { get; set; }
        public string? StateProvinceCode { get; set; }
        public string? CountryRegionCode { get; set; }
    }
}

===============================================
And here is the code of the module doing the calling:
===============================================

C#:
@page "/fetchdata"

<PageTitle>People Edit</PageTitle>

@using BlazorServerApp.Data

@inject DataAccessService PeopleService

<h1>People Edit</h1>

<p>This component demonstrates fetching data from a service.</p>

@if (PeopleService == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>FirstName</th>
                <th>Middle</th>
                <th>LastName</th>
                <th>Suffix</th>

            </tr>
        </thead>
        <tbody>
            @foreach (var Person in PeopleService)
            {
                <tr>
                    <td>@Person.Firstname</td>
                    <td>@Person.Middle</td>
                    <td>@Person.LastName</td>
                    <td>@Person.Suffix</td>
                
                </tr>
            }
        </tbody>
    </table>
}

@code {
    private DataAccessService[]? Person;

    protected override async Task OnInitializedAsync() => Person = await DataAccessService.GetPersonList();
 
  
}
 
Last edited by a moderator:
The first error message is as it says. A foreach statement is syntactic sugar. Under the hood, the code calls the IEnumerable.GetEnumerator method to get an IEnumerator object and then calls its MoveNext method on each iteration. That means that whatever is the subject of your foreach loop must implement the IEnumerable interface. Clearly, the DataAccessService object that you're trying to loop over doesn't implement that interface.

I'm not sure exactly what type(s) you're dealing with there but I would expect that PeopleService should refer to an instance of DataAccessService and you should be calling GetPersonList on that to get an object that implements IEnumerable, i.e. an array or collection of some sort, then you should be looping over that. It would be logical that you use a variable named people to refer to that list and then use something like this:
C#:
foreach (var person in people)
 
The first error message is as it says. A foreach statement is syntactic sugar. Under the hood, the code calls the IEnumerable.GetEnumerator method to get an IEnumerator object and then calls its MoveNext method on each iteration. That means that whatever is the subject of your foreach loop must implement the IEnumerable interface. Clearly, the DataAccessService object that you're trying to loop over doesn't implement that interface.

I'm not sure exactly what type(s) you're dealing with there but I would expect that PeopleService should refer to an instance of DataAccessService and you should be calling GetPersonList on that to get an object that implements IEnumerable, i.e. an array or collection of some sort, then you should be looping over that. It would be logical that you use a variable named people to refer to that list and then use something like this:
C#:
foreach (var person in people)

Thanks for your response. My issue is, I got this to work before without defining GetEnumerator, and I'm reading that rarely should one have to define it, that foreach handles all the details.
 
Where did I say or even imply that you needed to define GetEnumerator? I just looked at your C# code more closely and understand your types a bit better now. Please read what I actually wrote in my previous post. You loop over lists. I told you to call GetPersonList and loop over the results. Looking at your code, I see that GetPersonList returns a List<Person>. That sounds like a list to me.
 
Where did I say or even imply that you needed to define GetEnumerator? I just looked at your C# code more closely and understand your types a bit better now. Please read what I actually wrote in my previous post. You loop over lists. I told you to call GetPersonList and loop over the results. Looking at your code, I see that GetPersonList returns a List<Person>. That sounds like a list to me.

Sorry, I misinterpreted your response.
 
I should have looked more closely at your C# code - or at all for that matter - to get a better idea of the types you were using but it's important that you read our responses carefully. When someone asks for help and you provide the solution, it's a bit frustrating to have to come back and say the same thing again.
 
Back
Top Bottom