Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In C#, when does Type.FullName return null?

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".

Question

Can someone modify my code to give simple examples of each way in which Type.FullName can be null?

like image 490
Tyson Williams Avatar asked Jan 08 '16 06:01

Tyson Williams


People also ask

What is %A in C?

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.

What is << in C?

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.

What is the use of in C?

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.


2 Answers

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

  1. a generic type parameter;
  2. an array type, pointer type, or byref type based on a type parameter; or
  3. a generic type that is not a generic type definition but contains unresolved type parameters.

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***/
like image 178
Tyson Williams Avatar answered Sep 16 '22 16:09

Tyson Williams


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 is G`1, and we can round trip this type from Type.GetType(G`1). But we can build more complicated generic types, such as G<S> (type G<> bound with the generic parameter from the method M<>); 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])
like image 42
Rahul Tripathi Avatar answered Sep 20 '22 16:09

Rahul Tripathi