108. The maybe monad and nested null checking - If extension method

בהמשך לשבוע האולי טוב,

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

1
ZipCode zipCode = company.Workers[0].Address.ZipCode;

מה הבעיה כאן? כרגיל הכל יכול להיות null, אבל בנוסף לכך ייתכן שבמערך Workers אין תוצאות.

השיטה הקלאסית לפתור בעיה כזו היא:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
ZipCode zipCode = null;
if (company != null)
{
if ((company.Workers != null) && (company.Workers.Length > 0))
{
Person worker = company.Workers[0];
if ((worker != null) && (worker.Address != null))
{
zipCode = worker.Address.ZipCode;
}
}
}

כמות הקוד שאנחנו מבצעים כאן רק כדי לגשת לProperty היא די מכובדת.

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

1
2
3
4
5
6
7
8
9
10
11
12
public static TSource If<TSource>
(this TSource source,
Func<TSource, bool> predicate)
where TSource : class
{
if ((source != null) && predicate(source))
{
return source;
}
return null;
}

זה מחזיר לנו null אם הפרדיקט אינו מתקיים, אחרת מחזיר את האובייקט שקיבלנו לפונקציה.

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

1
2
3
4
5
ZipCode zipCode = company.With(x => x.Workers)
.If(x => x.Length > 0)
.With(x => x[0])
.With(x => x.Address)
.With(x => x.ZipCode);

או לחלופין ככה:

1
2
3
4
ZipCode zipCode = company.If(x => (x.Workers != null) && (x.Workers.Length > 0))
.With(x => x.Workers[0])
.With(x => x.Address)
.With(x => x.ZipCode);

באופן דומה, נוכל ליצור Extension Method מקביל בשם Unless:

1
2
3
4
5
6
7
8
9
10
11
12
public static TSource Unless<TSource>
(this TSource source,
Func<TSource, bool> predicate)
where TSource : class
{
if ((source == null) || predicate(source))
{
return null;
}
return source;
}

שמחזירה את האובייקט שקיבלנו לפונקציה, רק אם הפרדיקט לא מתקיים, ואחרת null.

באמצעותה נוכל לכתוב את אותו הדבר בצורה הבאה:

1
2
3
4
5
ZipCode zipCode = company.With(x => x.Workers)
.Unless(x => x.Length == 0)
.With(x => x[0])
.With(x => x.Address)
.With(x => x.ZipCode);

המשך יום אולי טוב

שתף