简体   繁体   中英

Why can't GetType() on a value type be replaced with a string literal at compile time?

EDIT : This question is based on the misconception that GetType() returns a string.

I'm trying to get a better handle on how C# works, so this question is more theoretical than practical.

As I understand it, calling GetType on a value type requires boxing and then calling the method. Since value types can't be inherited from, though, the type is known at compile time, so why can't the compiler simply replace the call to GetType() with a string literal?

Or is this something that could be done, but isn't considered necessary since there wouldn't be much need to call GetType on an unboxed value type anyway?

Let's consider the question you might have asked had you not had the misconception that GetType returns a string. Can the compiler compile

Foo foo = whatever;
Type t = foo.GetType();

as

Type t = typeof(Foo);

Yes, that would be a legal optimization. The compiler doesn't do that optimization because it would be a waste of the compiler team's time to do that optimization when they could be doing an optimization that actually makes a difference. Let's think about the proposed optimization.

  • Is there a new GetType method on Foo ? If so, then it can do anything. The compiler team has to detect calls to the original GetType . And then write test cases that ensure that the optimization is not applied in these cases.
  • It is incorrect if the receiver has any side effect. The compiler team would have to detect side effects and suppress the optimization in those cases, or implement the optimization in a manner that preserved side effects. And again write the test cases.
  • Those side effects include the possible null dereference exception in the case where we have Foo? instead of Foo , so you'd have to have a special case for that in the compiler.
  • What about GetType on a generic that might be a value type? There are a bunch of cases to consider there, and again, these increase the design, implementation, and testing cost of the optimization.
  • The optimization saves a single boxing penalty. The code by supposition is about to do an unnecessary reflection. Does that strike you as code that is on the critical path for the application to achieve high performance? Don't eliminate the boxing; eliminate the reflection!
  • An optimization that optimizes code that no one writes in the first place is not a useful optimization. Why would you do reflection to determine the type of an expression that you already know the type of at compile time? Sensible people don't write this code in the first place, so there is no need to optimize it.
  • Or put another way: if you accidentally write code the way that produces a boxing conversion, and you want to eliminate it, you can do so trivially. There's no need for the compiler to do it for you when it is easy to do yourself.

So for all these reasons and more, the cost of the optimization is higher than the benefit it produces.

For a longer but similar discussion on how to evaluate proposed optimizations, see this answer from yesterday: Weird behaviour of c# compiler due caching delegate

In an unboxed value type, GetType will always return the type of the variable. You already know the type of the variable, so what is the advantage to begin with? Simply use nameof on the type if you want the name:

var i = 1;
var iKnowTheType = nameof(System.Int32); //is this evaluated at compile time?
var s = "Int32";
var areSame = ReferenceEquals(iKnowTheType, s); //returns true!

iKnowTheType and s are the same string, which means nameof(System.Int32) and the literal "Int32" are basically the same thing (read about string interning for more accurate information on this subject).

GetType returns the runtime type of an object. In unboxed value types it will, again, always be the variable's type, but the key differnce here is that the type is evaluated at runtime:

var i = 1;
var iDontKnowTheType = i.GetType().Name;
var s = "Int32";
var areSame = ReferenceEquals(iDontKnowTheType, s); //returns false!
var areEqual = iDontKnowTheType  == s; //returns true

Here, the compiler can't intern iDontKnowTheType because that particular string is evaluated at runtime.

GetType() returns a Type object. That object does not exist at compile time, only at runtime.

Also that object has lots of metadata and other runtime data attached to it, so it can be used for much more than just a 'typename comparison', just think of Reflection and Serialization.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM