(1 item) |
|
(1 item) |
|
(5 items) |
|
(1 item) |
|
(1 item) |
|
(2 items) |
|
(2 items) |
|
(4 items) |
|
(1 item) |
|
(6 items) |
|
(2 items) |
|
(4 items) |
|
(1 item) |
|
(4 items) |
|
(2 items) |
|
(1 item) |
|
(1 item) |
|
(1 item) |
|
(1 item) |
|
(1 item) |
|
(1 item) |
|
(1 item) |
|
(1 item) |
|
(2 items) |
|
(2 items) |
|
(5 items) |
|
(3 items) |
|
(1 item) |
|
(1 item) |
|
(1 item) |
|
(3 items) |
|
(1 item) |
|
(1 item) |
|
(2 items) |
|
(8 items) |
|
(2 items) |
|
(7 items) |
|
(2 items) |
|
(2 items) |
|
(1 item) |
|
(2 items) |
|
(1 item) |
|
(2 items) |
|
(4 items) |
|
(1 item) |
|
(5 items) |
|
(1 item) |
|
(3 items) |
|
(2 items) |
|
(2 items) |
|
(8 items) |
|
(7 items) |
|
(3 items) |
|
(7 items) |
|
(6 items) |
|
(1 item) |
|
(2 items) |
|
(5 items) |
|
(5 items) |
|
(7 items) |
|
(3 items) |
|
(7 items) |
|
(16 items) |
|
(10 items) |
|
(27 items) |
|
(15 items) |
|
(15 items) |
|
(13 items) |
|
(16 items) |
|
(15 items) |
The typeof
operator in C# generates code that returns a Type
object.
It does this in a way that is much more direct than an 'equivalent' call to Type.GetType
.
(I'm ignoring the overload that takes no parameters by the way. That's special.) You pass a string to
Type.GetType
and at runtime it attempts to locate the type object represented by that
string. The call to Type.GetType
can fail at runtime, throwing an exception when the string cannot be
resolved to a Type
object.
Compare this to how typeof
works. It uses a completely different approach: the
IL ldtoken
instruction. The IL for a typical typeof
looks like this:
ldtoken SomeClass
call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
where SomeClass
is the name of the class. Of course the class name isn't
what gets written out as the opcode parameter. If we look at
the definition of
ldtoken we see that in the compiled IL (i.e. the binary) its parameter is a metadata token. In this
case it'll be either a typedef
or a typeref
.
That metadata token essentially identifies a row in either the type definition or type reference
metadata table. By the time the JIT compiler has generated the executable code for the method that
contains the ldtoken
it will have resolved that metadata token into a reference to
the type. If the type cannot be located, JIT compilation of the method will fail. (And that would
only happen if something is rather bizarrely wrong in your deployment.) So you are
guaranteed that if you actually get as far as executing a typeof
expression, it is
guaranteed to succeed. Compare this to Type.GetType
, which definitely can fail.
For example, this code:
Type.GetType("System.Srting")
will JIT compile just fine, but will fail at runtime, because there's no such type.
The C# compiler won't even let you compile the 'equivalent' typeof
.
So I get a relatively warm fuzzy feeling about using typeof
- I like code that will only
be able to run if it can't fail. All other things being equal,
I prefer this to code that has potential runtime failure modes.
I've always been mildly perplexed that there's no equivalent way of retrieving a
MethodInfo
object. E.g. a hypothetical methodinfo(SomeClass.SomeMethod)
operator.
It's not up the top of my list of language features I want added, it just seems mildly inconsistent to
have the operator for getting Type
objects but not the corresponding FieldInfo
and
MethodInfo
objects. (Interestingly, there doesn't seem to be a direct way to retrieve
an EventInfo
in IL, so I can't really object to that one not being in the
language.)
Until recently, I had never looked into the details of this. I wasn't previously sure if this missing feature was just something C# chooses not to do, or whether it's because, it can't be done. But I recently had reason to generate some IL that does exacly this, so I can now say with confidence that it's possible, and it's just that C# doesn't supply a corresponding operator.
It took me a while to get it right, hence this blog entry. I went down a blind alley for some time trying
to use ldftn
. You use that when initializing a delegate. I just assumed that the opcode
means "load function token", but was getting no joy trying to use this in conjunction with MethodBase.GetMethod
.
I eventually realised that ldftn
is the wrong thing - that actually loads what is effectively a function
pointer, not a metadata token. To load the metadata token for a method, you actually use the same opcode as you do
for loading a class token. So the IL for the MethodInfo
equivalent of typeof
looks like
this:
ldtoken method void SomeClass::SomeMethod()
call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
...which seems kind of obvious now I look at it. Still, I hope I this might save
someone else from going down the blind alley of using ldftn
when it
should be ldtoken
.