37. Method group covariance

בהמשך לטיפ של אתמול,

נניח שיש לנו מחלקה כזאת שאחראית לבנות צורה:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class ShapeBuilder
{
private Builder m_Builder;
public Builder Builder
{
get
{
return m_Builder;
}
set
{
m_Builder = value;
}
}
}

כשהdelegate הוא מהסוג הזה ומוזרק מבחוץ (ככה החליט יוצר המחלקה)

1
public delegate Shape Builder(int x, int y);

וכתבנו כבר מתודה כזאת:

1
2
3
4
public static Circle BuildCircle(int x, int y)
{
//
}

כעת אנחנו רוצים להשתמש בה בShapeBuilder.

עם זאת, נראה כי אנחנו לא יכולים להשתמש בה מאחר והdelegate מחזיר Shape, והמתודה שלנו מחזירה Circle.

לכן נראה שיש לנו שתי ברירות:

  1. ליצור עוד מתודה עם חתימה שמחזירה Shape שתקרא למתודה שלנו
  2. להחליף את החתימה של המתודה שלנו.

אם נחשוב על זה עוד קצת, הגיוני שדווקא כן נוכל להכניס את המתודה לShapeBuilder, כי Circle הוא Shape.

מסתבר שבC# 2.0 הכניסו לנו תמיכה בזה, ובאמת השורות הבאה תתקמפלנה לנו!

1
2
ShapeBuilder builder = new ShapeBuilder();
builder.Builder = new Builder(BuildCircle);

אם נחזור למושגים של אתמול, אומרים שהסבה של method group (יענו מתודה) לdelegate היא covariant בערך ההחזר.

כלומר אם יש לנו

1
B : A

וחתימה של delegate שמחזירה A, נוכל להכניס לdelegate כזה מתודה עם אותה חתימה שמחזירה B במקום.

עם זאת, אין covariance ברמת הטיפוסים של הdelegate, כלומר אם יש לנו את השני הdelegateים

1
2
public delegate Shape Builder(int x, int y);
public delegate Circle CircleBuilder(int x, int y);

לא מתקיים

1
CircleBuilder : Builder

נמחיש זאת באמצעות דוגמת קוד:

1
2
3
4
5
6
7
Builder builder =
new Builder(BuildCircle); // Compiles
CircleBuilder circleBuilder =
new CircleBuilder(BuildCircle); // Still compiles
builder = circleBuilder; // Doesn't compile

המשך יום קו-וואריאנטי טוב

שתף