0

Are the two expressions guaranteed to be identical?

In a generic method Foo<T> where T : new() ... is this expression always true?

typeof(T) == new T().GetType()

I don't see how it could be false, but perhaps I'm missing an edge-case.

I don't think this is addressed in any of the following related questions:

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Brondahl
  • 7,402
  • 5
  • 45
  • 74
  • This code generates objects of the concrete System.RuntimeType object. [Quote:](https://learn.microsoft.com/en-us/dotnet/api/system.type?view=net-7.0) *all classes beginning with the word Runtime are created only once per object in the system and support comparison operations* – Hans Passant May 29 '23 at 13:27
  • A little tangential, but `typeof(T)` doesn't care about the constructor parameters of `T` are. `new T().GetType()` does: it requires a parameterless constructor. – ProgrammingLlama May 29 '23 at 13:42

4 Answers4

7

typeof(T) and new T().GetType() are not quite identical. In fact, new T().GetType() is not "safe".

Consider when T is an int? or something similar, then new T() will result in null - actually an instance of int? with HasValue = false, which is actually a struct. Boxing a nullable value type that has no value results in null, and calling a method on it that is inherited from object will box the value first. So new T().GetType() throws a null reference exception in this case.

is this expression always true
typeof(T) == new T().GetType()

It might be that it is never false (ie either true or does not evaluate to a value), but I may be overlooking some other strange edge case.

harold
  • 61,398
  • 6
  • 86
  • 164
  • 1
    I think that a constructor for `T` is welcome to throw an exception too, but I don't think that `typeof(T)` can throw. – Wyck May 29 '23 at 13:59
  • @Wyck I certainly agree that it's _permitted_ ... but I might dispute "welcome" :P :D – Brondahl Jun 21 '23 at 08:49
2

In a generic method Foo<T> where T : new() ... is this expression always true?

typeof(T) == new T().GetType()

Sadly, no. For reference types (including nullable reference types) with default constructors then yes, but this doesn't hold true for nullable value types.

Where T is int? or DateTime? or any other nullable value type, the result of new T() is null. Calling GetType() on null is of course going to result in a NullReferenceException. But let's try something else:

static Type? WhichType<T>(T value) => value?.GetType();

This won't throw an exception, but may return null. Now let's try it out:

var type1 = WhichType<int?>(0);
var type2 = WhichType((int?)0);

Since nullable value types are treated specially by the C# compiler, it's not entirely clear that the result of calling GetType() on a nullable value type will return the inner type, and it makes some sense. Sadly it doesn't help you much when someone calls your generic method with the wrong type.

And in case you're wondering, it works on any value type not just value primitives:

public struct TestType { }

var type1 = WhichType<DateTime?>(DateTime.Now);
var type2 = WhichType<TestType?>(new TestType());

Where this may be an issue is when you're trying to compare the type of a value with an expected type where T is a nullable value type. In this case you need to use a bit of code to figure things out.

var targetType = typeof(T);
if (targetType.IsConstructedGenericType &&
    targetType.GetGenericTypeDefinition() == typeof(Nullable<>)
)
    targetType = Nullable.GetUnderlyingType(targetType);

This will unwrap the Nullable<> from the outer type if necessary, allowing you to compare it to the an object instance type.

Corey
  • 15,524
  • 2
  • 35
  • 68
0

It depends what you mean. If you are instantiating T (your var x = new T();) and then immediately after writing

Type t1 =  x.GetType();

and

if (t1 == typeof(T)) {... } // probably always true by definition

but what if your T is say a non abstract class and has subclass R? Well that changes the picture, doesn't it? I mean GetType() is a run time type (not a static compile type like typeof(T)). So (pseudo-code here below)

var x = new T();
var t1 = x.GetType(); // T 
...
x = new R();
...
bool chk1 = t1 == typeof(T); // true;
t1 = x.GetType(); // R
bool chk2 = t1 == typeof(T); // false
LongChalk
  • 783
  • 8
  • 13
  • I'm unclear why you have hypothesized a materially different set of code when I gave the specific (valid) expression that I was asking about? – Brondahl May 29 '23 at 13:47
  • @Brondahl is it a materially different set of code? when you say "is this expression always true" what does the *always* imply? here above it is not true. run time typing and compile type typing are not *always* the same. – LongChalk Jun 21 '23 at 05:54
  • 1
    Yes, @LongChalk, `typeof(T) == new T().GetType()` and `typeof(T) == new R().GetType()` are materially different. As are "1 line expression" vs "a code block of 6+ lines, involving assignment to variables of values that never existed in the 1-line expression." – Brondahl Jun 21 '23 at 08:48
-1

I suppose they're always provide the same result. The difference is in that for typeof you don't have to create new instance of a T which is rather something good. Also it's semantically more obvious if you go with typeof to check type rather than creating instance of an object.