73. Dictionary Add extension method

כפי שציינתי הרבה פעמים בעבר, אחד מהמבנים שאני מוצא את עצמי משתמש בהם הרבה מאוד הוא משהו כזה:

1
Dictionary<string, ICollection<int>>

זהו Dictionary שהValues שלו הם Collection, למשל PKים של אנשים שהשם שלהם הוא מסוים וכו’.

הבעיה היא שממש לא נוח להוסיף לו ערכים, נצטרך לכתוב קוד כזה:

1
2
3
4
5
6
7
8
9
10
11
12
IDictionary<string, ICollection<int>> namesToPks =
new Dictionary<string, ICollection<int>>();
ICollection<int> requestedNamesPks;
if (!namesToPks.TryGetValue(givenName, out requestedNamesPks))
{
requestedNamesPks = new List<int>();
namesToPks.Add(givenName, requestedNamesPks);
}
requestedNamesPks.Add(givenPk);

במקום זאת אפשר לעשות את מה שאני מדבר עליו כבר שבוע וחצי.

ניצור Extension Method כזה:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public static void Add<TKey, TValue, TValueCollection>
(this IDictionary<TKey, TValueCollection> dictionary,
TKey key,
TValue value)
where TValueCollection : ICollection<TValue>, new()
{
TValueCollection requestedValue;
bool wasValueFound =
dictionary.TryGetValue(key, out requestedValue);
if (!wasValueFound)
{
requestedValue = new TValueCollection();
dictionary.Add(key, requestedValue);
}
requestedValue.Add(value);
}

עכשיו נוכל לכתוב קוד כזה בכיף ובניחותא:

1
2
3
4
IDictionary<string, List<int>> namesToPks =
new Dictionary<string, List<int>>();
namesToPks.Add(givenName, givenPk);

שימו לב שהקומפיילר מגלה Implicitly מהם הפרמטרים הגנריים!

יותר יפה, לא?

הבעיה היחידה כאן היא שאנחנו חייבים של TValueCollection יהיה Constructor ולכן לא יכול להיות ICollection<TValue>.

במקום זאת נוכל לעשות Extension Method טיפה יותר גנרי:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static void Add<TKey, TValue, TValueCollection, TCollection>
(this IDictionary<TKey, TValueCollection> dictionary,
TKey key,
TValue value)
where TValueCollection : ICollection<TValue>
where TCollection : TValueCollection, new()
{
TValueCollection requestedValue;
bool wasValueFound =
dictionary.TryGetValue(key, out requestedValue);
if (!wasValueFound)
{
requestedValue = new TCollection();
dictionary.Add(key, requestedValue);
}
requestedValue.Add(value);
}

וליצור שני overloadים:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static void Add<TKey, TValue, TValueCollection>
(this IDictionary<TKey, TValueCollection> dictionary,
TKey key,
TValue value)
where TValueCollection : ICollection<TValue>, new()
{
dictionary.Add
<TKey, TValue, TValueCollection, TValueCollection>
(key, value);
}
public static void Add<TKey, TValue>
(this IDictionary<TKey, ICollection<TValue>> dictionary,
TKey key,
TValue value)
{
dictionary.Add
<TKey, TValue, ICollection<TValue>, List<TValue>>
(key, value);
}

וכעת נוכל לקרוא בשתי הדרכים:

1
2
3
4
IDictionary<string, ICollection<int>> namesToPks =
new Dictionary<string, ICollection<int>>();
namesToPks.Add(givenName, givenPk);

וגם בדרך הזו:

1
2
3
4
IDictionary<string, List<int>> namesToPks =
new Dictionary<string, List<int>>();
namesToPks.Add(givenName, givenPk);

שיהיה אחלה יום מורחב

שתף