C# yield return make(reader) not clear

T.Zacks 3,996 Reputation points
2022-10-13T13:01:40.357+00:00

this line is not clear yield return make(reader);

what is the meaning of this line ? Func<IDataReader, T> make

why make has IDataReader & T ?

see sample code taken from here https://stackoverflow.com/a/39496

public IEnumerable<T> Read<T>(string sql, Func<IDataReader, T> make, params object[] parms)  
{  
    using (var connection = CreateConnection())  
    {  
        using (var command = CreateCommand(CommandType.Text, sql, connection, parms))  
        {  
            command.CommandTimeout = dataBaseSettings.ReadCommandTimeout;  
            using (var reader = command.ExecuteReader())  
            {  
                while (reader.Read())  
                {  
                    yield return make(reader);  
                }  
            }  
        }  
    }  
}  

if i need to read first and last name and salary from db and sql return 5 records then how above function can read those data by
return make(reader)?

Thanks

Developer technologies | C#
0 comments No comments
{count} votes

Accepted answer
  1. Michael Taylor 60,161 Reputation points
    2022-10-13T15:18:48.853+00:00

    You have a lot of basic C# questions here. Honestly the best thing to do is read the docs for C# as they explain everything. I have included links to the appropriate topics.

    yield return make(reader) is an iterator (docs). In the special case of a method that returns IEnumerable<T>, C# allows you to use iterator syntax to return 1 item at a time from the method rather than stuffing the results into a temporary collection. The compiler generates an IEnumerable<T> wrapper that keeps calling your method like a coroutine until the method finishes executing. Each time yield is called the value is returned as the next "result" from the method. When the method is called by the generated code the next time it resumes from there (rather than from the beginning like a normal method). This is an advanced concept and honestly you don't need to understand how it works to use it. The closest equivalent code without an iterator would look something like this).

       public IEnumerable<T> Read<T>(string sql, Func<IDataReader, T> make, params object[] parms)  
        {  
            var results = new List<T>();  
         
            using (var connection = CreateConnection())  
            {  
                using (var command = CreateCommand(CommandType.Text, sql, connection, parms))  
                {  
                    command.CommandTimeout = dataBaseSettings.ReadCommandTimeout;  
                    using (var reader = command.ExecuteReader())  
                    {  
                        while (reader.Read())  
                        {  
                            results.Add(make(reader));  
                        }  
                    }  
                }  
            };  
         
            return results;  
        }  
    

    Func<IDataReader, T> is a delegate (docs). In other languages they are called function objects. It allows you to treat a function as data and pass it to other functions or store in variables. Func is a built in function type that says "any method that accepts an IDataReader and returns T can be used here". You pass in the function (with matching signature) you want called and each time through the while loop it calls your function, passing it the reader variable's current value. Delegates are heavily used in LINQ and programming in general these days.

       IEnumerable<string> results = Read<string>("my sql", GetAString);  
       IEnumerable<string> results2 = Read<string>("my sql", GetADifferentString);  
         
       string GetAString ( IDataReader reader )  
       {  
          return "A String";  
       }  
         
       string GetADIfferentString ( IDataReader reader )  
       {  
          return "A Different String";  
       }  
    

    IDataReader (docs) is an interface that allows you to enumerate the results of a database result set. Each time you read the next "row" the reader contains that row's data. In your example code the method that you pass to the call gets the reader and presumably retrieves the data from the current row. It is called for each row because of the while loop. For each row it is returning the results of that row. The method doesn't know what it'll return so it uses a generic method (docs) to represent the data that is being created as a type called T. This makes the code work with any type.

       IEnumerable<Product> products = Read<Product>("my sql", ReadProduct);  
       IEnumerable<Order> orders = Read<Order>("my sql", ReadOrder);  
         
       Product ReadProduct ( IDataReader reader )  
       {  
          //return a Product from the current row's data  
       }  
         
       Order ReadOrder ( IDataReader reader )  
       {  
          //return an Order from the current row's data  
       }  
    

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.