52. IEnumerable pitfalls

פעם קודמת ראינו איך ממומש foreach.

נזכיר, foreach, לדוגמה כזה:

1
2
3
4
foreach (Person person in people)
{
// Do stuff
}

זה בעצם syntactic sugar ל

1
2
3
4
5
6
7
IEnumerator enumerator = people.GetEnumerator();
while (enumerator.MoveNext())
{
Person person = (Person) enumerator.Current;
// Do stuff
}

הבעיה – כפי שאנחנו רואים יכול להיות לנו IEnumerator שמכיל Type אחד, והforeach יעבוד לנו גם כשנרוץ עליו עם Type אחר.

למשל, הקוד הבא יתקמפל:

1
2
3
4
5
6
IEnumerable people;
foreach (Fruit person in people)
{
// Do stuff
}

ונחטוף Exception על הסבה לא נכונה בזמן ריצה.


בC# 2.0, כידוע, נוספו Generics לשפה והיינו מצפים שהם ידעו לדאוג לכך שהקוד לא יתקמפל.

אם באמת נעשה משהו כזה:

1
2
3
4
5
6
IEnumerable<Person> people;
foreach (Fruit person in people)
{
// Do stuff
}

זה אכן לא יתקמפל.

Cannot convert type ‘Person’ to ‘Fruit’

האם Generics הצילו אותנו?

לא לגמרי


הסבות הן מהשטן,

אם יהיה לנו משהו כזה:

1
2
3
public interface IPerson
public class Person : IPerson
public class Fruit

וכעת נעשה משהו כזה:

1
2
3
4
5
6
IEnumerable<IPerson> people;
foreach (Fruit person in people)
{
// Do stuff
}

הקוד שוב יתקמפל!

הסיבה היא שאמנם Fruit אינו מממש IPerson, אבל אולי יש מישהו שיורש מFruit שכן מממש IPerson?


נוכל לפתור את הבעיה האחרונה אם המחלקה שלנו היא sealed:

1
public sealed class Fruit

במקרה כזה:

1
2
3
4
5
6
IEnumerable<IPerson> people;
foreach (Fruit person in people)
{
// Do stuff
}

לא מתקמפל. אנחנו מקבלים את השגיאה הבאה בזמן קימפול:

Cannot convert type ‘IPerson’ to ‘Fruit’

מאחר וFruit אינו מממש IPerson, והוא sealed, לא ייתכן שיש מישהו שיורש מFruit שכן מממש IPerson.


מסקנות שכדאי לקחת מכאן:

  1. כאשר אתם עובדים עם דברים שמממשים סתם IEnumerable, צריך מאוד להיזהר על הType שעושים איתו foreach. הנושא כאוב מאוד לגבי Collectionים מFramework 1.0 שלא הועברו לממשק הגנרי, ביניהם הCollectionים שבאו מSystem.Data (ביניהם DataTable וכל החברים), והCollectionים שבאו מSystem.Windows.Forms.
  2. כאשר אתם עובדים עם IEnumerable של ממשק, גם עליכם להיזהר!
  3. תשתדלו להפוך מחלקות לsealed אם אתם לא רוצים שירשו מהן.

המשך יום בר מנייה טוב

שתף