Documentation of Type.Namespace property states:
If the current Type represents a constructed generic type, this property returns the namespace that contains the generic type definition. Similarly, if the current Type represents a generic parameter T, this property returns the namespace that contains the generic type definition that defines T.
If the current Type object represents a generic parameter, this property returns null.
When does Type.Namespace return null if instance represents a generic parameter like in the last cited paragraph? Or is the documentation wrong and the the statements in bold are actually contradicting each other?
To investigate I wrote some simple code, but I haven't found any answer. All the Console.WriteLine statements print something.
using System;
namespace TypeDemo
{
internal static class Program
{
public static void Main()
{
var g = new G<int>();
g.M(4);
Console.WriteLine(typeof(G<>).Namespace);
}
}
public class G<T>
{
static G()
{
Console.WriteLine(typeof(T).Namespace);
}
public G()
{
Console.WriteLine(typeof(T).Namespace);
Console.WriteLine(GetType().Namespace);
}
public void M<S>(S s)
{
Console.WriteLine(typeof(S).Namespace);
Console.WriteLine(s.GetType().Namespace);
}
}
}
Note that all the types that you are printing are not generic parameters. Notice how when the methods are run, the type is already constructed. For example, when you do:
var g = new G<int>();
// which calls...
public G()
{
// T has become "int" here!
Console.WriteLine(typeof(T).Namespace);
Console.WriteLine(GetType().Namespace);
}
To get a Type that represents generic parameters, you can:
[call] the
GetGenericArgumentsmethod of aTypeobject that represents a generic type definition, or theGetGenericArgumentsmethod of aMethodInfoobject that represents a generic method definition.
For example:
Console.WriteLine(typeof(Foo.C<>).GetGenericArguments()[0].Namespace);
namespace Foo {
class C<T> {
public void Foo() {
}
}
}
and
Console.WriteLine(typeof(Foo.C).GetMethod("Foo").GetGenericArguments()[0].Namespace);
namespace Foo {
class C {
public void Foo<T>() {
}
}
}
Both of them prints Foo, and I have not been able to find a case where a generic type parameter is in a namespace, but its Namespace returns null. This means the actual behaviour matches this sentence:
Similarly, if the current Type represents a generic parameter T, this property returns the namespace that contains the generic type definition that defines T.
Docs are contradicting, but correct in principle. Type.Namespace returns null when the namespace is not available from generic definition. One way to get this is MakeGenericMethodParameter:
Type t=Type.MakeGenericMethodParameter(0);
Console.WriteLine("IsGenericParameter: "+t.IsGenericParameter);
Console.WriteLine("Namespace: "+(t.Namespace==null?"(null)":t.Namespace));
Another is to have a custom Type implementation (it's an abstract class everyone could derive from and override properties to do whatever they want).
Edit: Type.Namespace docs were fixed in PR https://github.com/dotnet/dotnet-api-docs/pull/7466/files