The MSDN for Type.FullName says that this property return
null if the current instance represents a generic type parameter, an array type, pointer type, or byreftype based on a type parameter, or a generic type that is not a generic type definition but contains unresolved type parameters.
I count five cases, and I find each one more unclear than the last. Here is my attempt to construct examples of each case.
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication {
public static class Program {
public static void Main(string[] args) {
GenericTypeParameter();
ArrayType();
PointerType();
ByRefTypeBasedOnTypeParameter();
NongenericTypeDefinitionWithUnresolvedTypeParameters();
Console.ReadKey();
}
public static void GenericTypeParameter() {
var type = typeof(IEnumerable<>)
.GetGenericArguments()
.First();
PrintFullName("Generic type parameter", type);
}
public static void ArrayType() {
var type = typeof(object[]);
PrintFullName("Array type", type);
}
public static void PointerType() {
var type = typeof(int*);
PrintFullName("Pointer type", type);
}
public static void ByRefTypeBasedOnTypeParameter() {
var type = null;
PrintFullName("ByRef type based on type parameter", type);
}
private static void NongenericTypeDefinitionWithUnresolvedTypeParameters() {
var type = null;
PrintFullName("Nongeneric type definition with unresolved type parameters", type);
}
public static void PrintFullName(string name, Type type) {
Console.WriteLine(name + ":");
Console.WriteLine("--Name: " + type.Name);
Console.WriteLine("--FullName: " + (type.FullName ?? "null"));
Console.WriteLine();
}
}
}
Which has this output.
Generic type parameter:
--Name: T
--FullName: null
Array type:
--Name: Object[]
--FullName: System.Object[]
Pointer type:
--Name: Int32*
--FullName: System.Int32*
ByRef type based on type parameter:
--Name: Program
--FullName: ConsoleApplication.Program
Nongeneric type definition with unresolved type parameters:
--Name: Program
--FullName: ConsoleApplication.Program
I am only one for five with two "blanks".
Can someone modify my code to give simple examples of each way in which Type.FullName can be null?
Modulus AND assignment operator. It takes modulus using two operands and assigns the result to the left operand. C %= A is equivalent to C = C % A. <<= Left shift AND assignment operator.
The << operator shifts the left-hand value left by the (right-hand value) bits. Your example does nothing! 1 shifted 0 bits to the left is still 1. However, 1 << 1 is 2, 1 << 2 is 4, etc.
In C/C++, the # sign marks preprocessor directives. If you're not familiar with the preprocessor, it works as part of the compilation process, handling includes, macros, and more.
So I noticed right away that the MSDN quote includes "or" twice in its list of cases, but it took me far too long to realize why. The reality is that there are three main cases with one of those three being split into three further cases. Using clearer punctuation, the cases are
I understood the first case, Rahul's answer directed me to this MSDN blog post that explains and give two examples of the last case, and now I can give examples of the remaining cases.
using System;
using System.Linq;
namespace ConsoleApplication {
public class GenericClass<T> {
public void ArrayMethod(T[] parameter) { }
public void ReferenceMethod(ref T parameter) { }
}
public class AnotherGenericClass<T> : GenericClass<T> { }
public static class Program {
public static void Main(string[] args) {
GenericTypeParameter();
ArrayTypeBasedOnTypeParameter();
PointerTypeBasedOnTypeParameter();
ByRefTypeBasedOnTypeParameter();
NongenericTypeDefinitionWithUnresolvedTypeParameters();
Console.ReadKey();
}
public static void GenericTypeParameter() {
var type = typeof(GenericClass<>)
.GetGenericArguments()
.First();
PrintFullName("Generic type parameter", type);
}
public static void ArrayTypeBasedOnTypeParameter() {
var type = typeof(GenericClass<>)
.GetMethod("ArrayMethod")
.GetParameters()
.First()
.ParameterType;
PrintFullName("Array type based on type parameter", type);
}
/*
* Would like an actual example of a pointer to a generic type,
* but this works for now.
*/
public static void PointerTypeBasedOnTypeParameter() {
var type = typeof(GenericClass<>)
.GetGenericArguments()
.First()
.MakePointerType();
PrintFullName("Pointer type based on type parameter", type);
}
public static void ByRefTypeBasedOnTypeParameter() {
var type = typeof(GenericClass<>)
.GetMethod("ReferenceMethod")
.GetParameters()
.First()
.ParameterType;
PrintFullName("ByRef type based on type parameter", type);
}
private static void NongenericTypeDefinitionWithUnresolvedTypeParameters() {
var type = typeof(AnotherGenericClass<>).BaseType;
PrintFullName("Nongeneric type definition with unresolved type parameters", type);
}
public static void PrintFullName(string name, Type type) {
Console.WriteLine(name + ":");
Console.WriteLine("--Name: " + type.Name);
Console.WriteLine("--FullName: " + (type.FullName ?? "null"));
Console.WriteLine();
}
}
}
/***Output***
Generic type parameter:
--Name: T
--FullName: null
Array type based on type parameter:
--Name: T[]
--FullName: null
Pointer type based on type parameter:
--Name: T*
--FullName: null
Byref type based on type parameter:
--Name: T&
--FullName: null
Nongeneric type definition with unresolved type parameters:
--Name: GenericClass`1
--FullName: null
***Output***/
You can check this MSDN blog which demonstrates when Type.FullName
returns null
.
For instance, suppose we have an assembly compiled with the following C# code:
class G<T> { public void M<S>() { } }
typeof(G<>).FullName
isG`1
, and we can round trip this type from Type.GetType(G`1
). But we can build more complicated generic types, such asG<S>
(typeG<>
bound with the generic parameter from the methodM<>
); in order to identify such type with a string, a lot of extra information is need.Below are some examples where Type.FullName returns null.
class G<T> {
public class C { }
public void M(C arg) { }
}
class G2<T> : G<T> { }
string s1 = typeof(G<>).GetGenericArguments()[0].FullName;
// T in G<T>: generic parameter
string s2 = typeof(G<>).GetMethod("M").GetParameters()[0].ParameterType.FullName;
// check out the IL, it is G`1/C<!T> (not generic type definition)
// Related topic, see this
string s3 = typeof(G2<>).BaseType.FullName;
// base type of G2<>, which is not generic type definition either
// it equals to typeof(G<>).MakeGenericType(typeof(G2<>).GetGenericArguments()[0])
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With