Reflection (part 1, basics, advanced), types and generic types
I explained generic types yesterday. Discussing reflection is a bit early on this post. I will concentrate on some basic and slightly advanced material about generics and nullables.
Reflection is used to obtain type information at run-time.
C# offers the typeof() keyword for types and the GetType() method for objects.
The is keyword uses both and follows the pattern: object is type
AnyClass c = new AnyClass(); Type a1 = typeof(int); // typeof(type) Type a2 = c.GetType(); // object.GetType() bool b = c is int; // object is type
The is keyword returns true if an instance is in the inheritance tree. This results in a very specific behaviour:
class Animal { } class Cat : Animal { } public static void Generics6() { // easy going Animal lAnimal = new Animal(); Console.WriteLine(lAnimal.GetType() == typeof(Animal)); // true Console.WriteLine(lAnimal is Animal); // true Console.WriteLine(lAnimal.GetType() == typeof(Cat)); // false // and now it gets tricky Animal lCat = new Cat(); Console.WriteLine(lCat.GetType() == typeof(Animal)); // false ! Console.WriteLine(lCat is Animal); // true ! Console.WriteLine(lCat.GetType() == typeof(Cat)); // true } //
The typeof(T) also has its own behaviour. It is does not care what true instance type it is looking at. It returns the result of the last cast operation. Here is an example program to highlight this fact:
static void Print<T>(T t, string xInfo) { Console.WriteLine(xInfo.PadRight(22) + "| typeof(T) " + typeof(T).Name.PadRight(7) + "| GetType(): " + t.GetType().Name.PadRight(7) + "| is Cat: " + (t is Cat).ToString().PadRight(6) + "| is Animal: " + (t is Animal)); } // public static void Confusing() { Animal lAnimal = new Cat(); Cat lCat = new Cat(); Print(lCat, "Print(lCat)"); Print<Cat>(lCat, "Print<Cat>(lCat)"); Print(lAnimal, "Print(lAnimal)"); Print<Animal>(lAnimal, "Print<Animal>(lAnimal)"); Print<Animal>(lCat, "Print<Animal>(lCat)"); Print((Animal)lCat, "Print((Animal)lCat)"); //Print<Cat>(lAnimal); // compiler error } //
example output in a table:
Command typeof(T) GetType() Is Cat? Is Animal? Print(lCat) Cat
Cat
True
True
Print<Cat>(lCat) Cat
Cat
True
True
Print(lAnimal) Animal
Cat
True
True
Print<Animal>(lAnimal) Animal
Cat
True
True
Print<Animal>(lCat) Animal
Cat
True
True
Print((Animal)lCat) Animal
Cat
True
True
Walk through the example of a generic method:
private static void Generics4<T>(T t) { Type lType = typeof(T); Console.WriteLine("Analysing variable " + t + Environment.NewLine); Console.WriteLine("using typeof()"); if (lType == typeof(int)) Console.WriteLine(typeof(T).ToString() + " is an integer"); else if (lType == typeof(string)) Console.WriteLine(typeof(T).ToString() + " is a string"); Console.WriteLine("\nusing the \"is\" keyword"); if (t is int) Console.WriteLine(typeof(T).ToString() + " is an integer"); else if (t is string) Console.WriteLine(typeof(T).ToString() + " is a string"); Console.WriteLine("\nusing GetType()"); if (t.GetType() == typeof(int)) Console.WriteLine(typeof(T).ToString() + " is an integer"); else if (t.GetType() == typeof(string)) Console.WriteLine(typeof(T).ToString() + " is a string"); } // public static void Generics5() { Generics4(5); Console.WriteLine(); Generics4("hello"); Console.WriteLine(); int? i = 666; Generics4(i); Console.ReadLine(); } //
Analysing variable 5
using typeof()
System.Int32 is an integerusing the “is” keyword
System.Int32 is an integerusing GetType()
System.Int32 is an integerAnalysing variable hello
using typeof()
System.String is a stringusing the “is” keyword
System.String is a stringusing GetType()
System.String is a stringAnalysing variable 666
using typeof()
using the “is” keyword
System.Nullable`1[System.Int32] is an integerusing GetType()
System.Nullable`1[System.Int32] is an integer
The Type class offers far more information about the object we are using.
class GenericClass7<T> { public void HelloWorld() { } } private class AnyClass { } public static void Generics7<T>(T t) { Type lType = typeof(T); Console.WriteLine("value".PadRight(30) + t); Console.WriteLine("IsPublic".PadRight(30) + lType.IsPublic); Console.WriteLine("IsGenericParameter".PadRight(30) + lType.IsGenericParameter); Console.WriteLine("IsGenericType".PadRight(30) + lType.IsGenericType); Console.WriteLine("IsGenericTypeDefinition".PadRight(30) + lType.IsGenericTypeDefinition); Console.WriteLine("IsValueType".PadRight(30) + lType.IsValueType); Console.WriteLine("Name".PadRight(30) + lType.Name); Console.WriteLine("BaseTypeName".PadRight(30) + lType.BaseType.Name); foreach (MemberInfo lMember in lType.GetMembers()) { Console.WriteLine("Member".PadRight(30) + lMember.Name); } Console.WriteLine(string.Empty.PadRight(50, '-')); } // public static void RunTest() { Console.WriteLine("integer:\n"); Generics7(1); Console.WriteLine("nullable integer:\n"); Generics7(new Nullable<int>(2)); Console.WriteLine("string:\n"); Generics7("hello"); Console.WriteLine("class:\n"); Generics7(new AnyClass()); Console.WriteLine("generic class:\n"); Generics7(new GenericClass7<double>()); Console.WriteLine(); } //
example output:
integer:
value 1
IsPublic True
IsGenericParameter False
IsGenericType False
IsGenericTypeDefinition False
IsValueType True
Name Int32
BaseTypeName ValueType
Member CompareTo
Member CompareTo
Member Equals
Member Equals
Member GetHashCode
Member ToString
Member ToString
Member ToString
Member ToString
Member Parse
Member Parse
Member Parse
Member Parse
Member TryParse
Member TryParse
Member GetTypeCode
Member GetType
Member MaxValue
Member MinValue
————————————————–
nullable integer:value 2
IsPublic True
IsGenericParameter False
IsGenericType True
IsGenericTypeDefinition False
IsValueType True
Name Nullable`1
BaseTypeName ValueType
Member get_HasValue
Member get_Value
Member GetValueOrDefault
Member GetValueOrDefault
Member Equals
Member GetHashCode
Member ToString
Member op_Implicit
Member op_Explicit
Member GetType
Member .ctor
Member HasValue
Member Value
————————————————–
string:value hello
IsPublic True
IsGenericParameter False
IsGenericType False
IsGenericTypeDefinition False
IsValueType False
Name String
BaseTypeName Object
Member Join
Member Join
Member Join
Member Join
Member Join
Member Equals
Member Equals
Member Equals
Member Equals
Member Equals
Member op_Equality
Member op_Inequality
Member get_Chars
Member CopyTo
Member ToCharArray
Member ToCharArray
Member IsNullOrEmpty
Member IsNullOrWhiteSpace
Member GetHashCode
Member get_Length
Member Split
Member Split
Member Split
Member Split
Member Split
Member Split
Member Substring
Member Substring
Member Trim
Member TrimStart
Member TrimEnd
Member IsNormalized
Member IsNormalized
Member Normalize
Member Normalize
Member Compare
Member Compare
Member Compare
Member Compare
Member Compare
Member Compare
Member Compare
Member Compare
Member Compare
Member Compare
Member CompareTo
Member CompareTo
Member CompareOrdinal
Member CompareOrdinal
Member Contains
Member EndsWith
Member EndsWith
Member EndsWith
Member IndexOf
Member IndexOf
Member IndexOf
Member IndexOfAny
Member IndexOfAny
Member IndexOfAny
Member IndexOf
Member IndexOf
Member IndexOf
Member IndexOf
Member IndexOf
Member IndexOf
Member LastIndexOf
Member LastIndexOf
Member LastIndexOf
Member LastIndexOfAny
Member LastIndexOfAny
Member LastIndexOfAny
Member LastIndexOf
Member LastIndexOf
Member LastIndexOf
Member LastIndexOf
Member LastIndexOf
Member LastIndexOf
Member PadLeft
Member PadLeft
Member PadRight
Member PadRight
Member StartsWith
Member StartsWith
Member StartsWith
Member ToLower
Member ToLower
Member ToLowerInvariant
Member ToUpper
Member ToUpper
Member ToUpperInvariant
Member ToString
Member ToString
Member Clone
Member Trim
Member Insert
Member Replace
Member Replace
Member Remove
Member Remove
Member Format
Member Format
Member Format
Member Format
Member Format
Member Copy
Member Concat
Member Concat
Member Concat
Member Concat
Member Concat
Member Concat
Member Concat
Member Concat
Member Concat
Member Concat
Member Concat
Member Intern
Member IsInterned
Member GetTypeCode
Member GetEnumerator
Member GetType
Member .ctor
Member .ctor
Member .ctor
Member .ctor
Member .ctor
Member .ctor
Member .ctor
Member .ctor
Member Chars
Member Length
Member Empty
————————————————–
class:value ConsoleApplication1.CGenerics+AnyClass
IsPublic False
IsGenericParameter False
IsGenericType False
IsGenericTypeDefinition False
IsValueType False
Name AnyClass
BaseTypeName Object
Member ToString
Member Equals
Member GetHashCode
Member GetType
Member .ctor
————————————————–
generic class:value ConsoleApplication1.CGenerics+GenericClass7`1[System.Double]
IsPublic False
IsGenericParameter False
IsGenericType True
IsGenericTypeDefinition False
IsValueType False
Name GenericClass7`1
BaseTypeName Object
Member HelloWorld
Member ToString
Member Equals
Member GetHashCode
Member GetType
Member .ctor
————————————————–
I guess there could be hundreds of posts just about reflection. This short explanation should be enough for today. Basically we would start digging ourselves deep into the System.Reflection.Emit namespace. We will touch this topic again when appropriate.
Posted on January 2, 2014, in Advanced, Basic, C#, Generics, Reflection and tagged C#, GetType, is, reflection, Source code, typeof. Bookmark the permalink. 1 Comment.
Pingback: Reflection (part 2, advanced), attributes | C# Hardcore Programming