In a class library called DataAccess I find the following declaration and usage:
public static class DataAccess
{
public delegate T LoadObject<T>(SqlDataReader dataReader);
public static Dictionary<TKey, TValue> GetDictionaryFromReader<TKey, TValue>(
Database database
, DbCommand dbCommand
, LoadObject<KeyValuePair<TKey, TValue>> loadMethod
)
{
Dictionary<TKey, TValue> _dictionary = new Dictionary<TKey, TValue>();
using (SqlDataReader dataReader = StoredProcedures.ExecuteSqlDataReader(database, dbCommand))
{
GenerateDictionary<TKey, TValue>(dataReader, ref _dictionary, loadMethod);
}
return _dictionary;
}
}
GetDictionaryFromReader above is called by this static method:
public static Dictionary<String, String> GetGroupTypesList()
{
Dictionary<string, string> dict = new Dictionary<string, string>();
Database database = CenestDatabaseFactory.CreateDatabase();
DbCommand dbCommand = database.GetStoredProcCommand(SP_LIST_GROUP_TYPES);
dict = DataAccess.GetDictionaryFromReader<string, string>(database, dbCommand, _loadGroupType);
return dict;
}
It passes "_loadGroupType" into "loadMethod". "_loadGroupType" looks like this:
private static KeyValuePair<string, string> _loadGroupType(SqlDataReader returnData)
{
KeyValuePair<string, string> entry =
new KeyValuePair<string, string>((string)returnData["Group_Type"], (string)returnData["Group_Type_Desc"]);
return entry;
}
I sort of "get" that the _loadGroupType method is being passed as a parameter into GetDictionaryFromReader. Okay, but why? And what is this delegate declaration syntax supposed to say?
public delegate T LoadObject<T>(SqlDataReader dataReader);
I'd really like to understand what is going on with this. You don't need to explain it yourself -- but can you point to something that will be able to make it clear to me?
Thanks!
Additional Note to @ReedCopsey:
So...
In this using statement:
using (SqlDataReader dataReader = StoredProcedures.ExecuteSqlDataReader(database, dbCommand))
{
GenerateDictionary<TKey, TValue>(dataReader, ref _dictionary, loadMethod);
}
Is C# smart enough to recognize that loadMethod needs the SqlDataReader passed to it, and does so -- because of the using statement and the initial delegate declaration? Because otherwise I can't see how the data reader makes it into the method.
Of course not! As per @ReedCopsey the GenerateDictionary method uses the SqlDataReader, Duh:
private static void GenerateDictionary<TKey, TValue>(
SqlDataReader dataReader
, ref Dictionary<TKey, TValue> dictionary
, LoadObject<KeyValuePair<TKey, TValue>> loadMethod
)
{
while (dataReader.Read())
{
KeyValuePair<TKey, TValue> kvp = loadMethod(dataReader);
dictionary.Add(kvp.Key, kvp.Value);
}
}
And what is this delegate declaration syntax supposed to say?
That is a delegate which is typed to be a method that accepts a SqlDataReader
as an input, and returns a generic type T
as the result.
In your case, the T
result is KeyValuePair<string,string>
.
Is C# smart enough to recognize that loadMethod needs the SqlDataReader passed to it, and does so -- because of the using statement and the initial delegate declaration? Because otherwise I can't see how the data reader makes it into the method.
No. The GenerateDictionary<TKey,TValue>
method is going to use the dataReader
passed into it to call the delegate.
The declaration public delegate T LoadObject<T>(SqlDataReader dataReader)
is expecting a SqlDataReader
and will return whatever type you want it to. Could be an int
, a List<string>
or even another delegate. That's because there's no generic constraint on the type T
and it is only associated with the return type of the delegate.
On the other hand, we have private static KeyValuePair<string, string> _loadGroupType(SqlDataReader returnData)
. This is a function that receives a SqlDataReader
and returns a... wait, it doesn't matter, could be anything! So the _loadGroupType
does "match" against the delegate LoadObject<T>
with T
= KeyValuePair<string, string>
and can be implicitly used as such.
If there was a delegate declared such as delegate KeyValuePair<string, string> D2(SqlDataReader reader);
it would also match, but without the generics this time. When the type doesn't matter for an operation (or it can be contrained), generics are your friend.
First the declaration says: LoadObject
will be a method that takes an SqlDataReader
and returns a T
, where T
is defined by the user.
Then GetDictionaryFromReader
says it needs a LoadObject<KeyValuePair<TKey, TValue>>
, so T
is KeyValuePair<TKey, TValue>
here, so it needs a method takes an SqlDataReader
and returns KeyValuePair<TKey, TValue>
.
At last, when you call GetDictionaryFromReader
, passing _loadGroupType
, it takes an SqlDataReader
and returns KeyValuePair<TKey, TValue>
, just fits what GetDictionaryFromReader
want.
I don't think there is anything diffcult to understand.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.