178. ConstructorInfo

ראינו בעבר איך אפשר לקבל Properties ומתודות של טיפוס מסוים בReflection.

ראינו גם שאפשר ליצור instance של טיפוס מסוים בעזרת Activator.CreateInstance.

(טיפים 139,146,158)

מדי פעם נתקל בשגיאה ביצירת טיפוס באמצעות Activator.CreateInstance כאשר לא ברור לאיזה Constructor התכוונו לקרוא.

למשל, נניח שיש לנו שני Constructorים:

1
2
3
4
5
6
7
8
9
10
public class Person
{
public Person(Person source)
{
}
public Person(string name)
{
}
}

ואנחנו מבצעים קריאה כזאת:

1
2
object person =
Activator.CreateInstance(typeof (Person), new object[] {null});

אז אנחנו נחטוף Exception:

Ambiguous match found.


מה הסיפור? null יכול להתאים לשני הConstructorים ולכן Activator.CreateInstance לא יודע לאיזה Constructor לנתב את הקריאה.

המקרה עם null הוא לא כזה מונפץ, מאחר וייתכן ואחד האובייקטים שאנחנו רוצים להעביר לConstructor הוא Instance ששווה לnull.

בנוסף, גם אם יהיו לנו שתי חתימות שאפשר להיכנס אליהן, הוא לא ידע לאן להיכנס:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Circle : Shape, IColored
{
public Circle()
{
}
public Circle(IColored source)
{
}
public Circle(Shape source)
{
}
}
Circle myCircle =
(Circle)Activator.CreateInstance(typeof (Circle), new Circle());

נחטוף Exception כיוון שהוא לא יודע לאן לנתב את הCircle.

איך אפשר לפתור את זה? כמו שיש MethodInfo שמתאר מתודות, יש גם ConstructorInfo המייצג metadata של Constructorים.

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

1
2
3
4
5
ConstructorInfo stringConstructorInfo =
typeof (Person).GetConstructor(new Type[] {typeof (string)});
Person myPerson =
(Person)stringConstructorInfo.Invoke(new object[] {null});

ככה לא נעוף.


יש דמיון בין ConstructorInfo לMethodInfo ולמעשה שניהם יורשים מהמחלקה MethodBase.

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

במקרה של MethodInfo צריכה להתבצע קריאה הדומה לפקודות הIL ששמן Call וCallvirt. במקרה של ConstructorInfo צריכה להתבצע קריאה הדומה לפקודת הIL ששמה newobj.

זו אחת הסיבות שאי אפשר להתייחס לConstructorים כמו מתודות רגילות, ולמשל אי אפשר ליצור delegate שמצביע לConstructor.

שיהיה המשך יום מידע בנוי טוב

שתף