141. More Type and generics

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

לפעמים אנחנו מעוניינים לעשות להפך – יש לנו Type גנרי שהוזרקו אליו הפרמטרים, ואנחנו מעוניינים לקבל את הטיפוס הגנרי (ללא הפרמטרים הגנריים המוזרקים), או לחלופין לקבל את הפרמטרים הגנריים המוזרקים.

כדי להשיג את הType הגנרי ללא הפרמטרים הגנריים המוזרקים, נוכל להשתמש בפונקציהGetGenericTypeDefinition:

1
2
Type closedDictionaryType = typeof (Dictionary<string,int>);
Type unboundDictionaryType = closedDictionaryType.GetGenericTypeDefinition(); // typeof(Dictionary<,>)

כדי לחלץ את הארגומנטים הגנריים נוכל להשתמש בפונקציה GetGenericArguments המחזירה לנו מערך של הארגומנטים הגנריים:

1
2
Type[] genericArguments = closedDictionaryType.GetGenericArguments();
// new[] {typeof (string), typeof (int)}

אם נשתמש GetGenericArguments על טיפוס שהוא Unbound, נקבל את הפרמטרים "הגנריים":

1
2
3
4
5
6
7
8
9
Type[] genericArguments = unboundDictionaryType.GetGenericArguments();
foreach (Type genericArgument in genericArguments)
{
Console.WriteLine(genericArgument);
}
// Prints:
// TKey
// TValue

הבעיה עם הפונקציות האלה היא שאם נקרא להן על טיפוס שאינו גנרי, נקבל Exception.

נוכל למנוע זאת ע"י בדיקה האם הטיפוס הנתון הוא גנרי:

הProperty ששמו IsGenericType מציין האם הטיפוס הנתון הוא גנרי (בין אם הוא closed ובין אם הוא unbound)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if (closedDictionaryType.IsGenericType)
{
// True
}
if (unboundDictionaryType.IsGenericType)
{
// True
}
if (typeof(string).IsGenericType)
{
// False
}

יש גם Property בשם IsGenericTypeDefinition שמציין האם הטיפוס הנתון הוא unbound:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if (closedDictionaryType.IsGenericTypeDefinition)
{
// False
}
if (unboundDictionaryType.IsGenericTypeDefinition)
{
// True
}
if (typeof(string).IsGenericTypeDefinition)
{
// False
}

בנוסף, נוכל לראות האם טיפוס מסוים הוא פרמטר גנרי (כמו שראינו למעלה):

1
2
3
4
5
6
7
Type keyType =
unboundDictionaryType.GetGenericArguments()[0];
if (keyType.IsGenericParameter)
{
// True
}

לבסוף, נוכל לראות את הConstraintים שיש על הטיפוסים הגנריים:

למשל, נניח שיש לנו מחלקה כזו:

1
2
3
public class Contrainted<T> where T : IComparable
{
}

(ראו גם טיפ מספר 29,30)

אז הקוד הבא ידפיס

1
2
3
4
5
6
7
8
9
10
11
12
13
Type comparableType = typeof (Contrainted<>);
Type firstGenericType =
comparableType.GetGenericArguments()[0];
Type[] constraints =
firstGenericType.GetGenericParameterConstraints();
foreach (Type constraint in constraints)
{
Console.WriteLine(constraint);
}
// typeof(IComparable)

ראו גם טיפ מספר 317

שיהיה שבוע טיפוסי טוב

שתף