C# - custom explicit conversion with checked/unchecked operator
I'm learning to write custom type conversions in C# and I have a question I can't manage to resolve with Google / MSDN / earlier posted SO items.
Normally, a C# program that narrows a numeric type does that via unchecked explicit conversion, e.g.:
int i = 256;
byte b = (byte)i; // b == 0
however, the following will give an overflow exception:
byte b = checked((byte)i);
My question is as 开发者_StackOverflow中文版follows: is the behavior of the checked / unchecked keyword implementable in an custom type conversion, e.g.:
class Foo {
public static explicit operator int(Foo bar) {
if (checked)
throw someEception
else
return some Foo to int conversion
}
}
Of course, the code above is not the answer, but does anyone know if something like this is possible?
checked
is a compile time thing. That is, its sole effect will be on the code block directly surrounded by a checked
statement, not the methods called in that block. Consequently, there wouldn't be a checked
and unchecked
context at run time that you may want to adjust the behavior of a function according to it.
Section 14.5.12 of the C# language spec explicitly enumerates all the operators on which the checked and unchecked keywords can have an effect.
User defined operators are not part of that list, so no, you cannot write a user-defined conversion operator that takes checked/unchecked into account.
checked
causes a "check for overflow" version of the appropriate CIL instruction to be generated by the compiler.
Here's a dump from IL Disassembler:
//000012: Int32 i = 42;
IL_0001: ldc.i4.s 42
IL_0003: stloc.0
//000013: Byte b1 = (Byte) i;
IL_0004: ldloc.0
IL_0005: conv.u1
IL_0006: stloc.1
//000014: Byte b2 = checked ((Byte) i);
IL_0007: ldloc.0
IL_0008: conv.ovf.u1
IL_0009: stloc.2
Does it solve your problem to simply do this:
class Foo {
public static explicit operator int(Foo bar) {
unchecked {
return some Foo to int conversion
}
}
}
As I commented on some answers, I think I got the answer I was looking for. Controlling checked/unchecked explicit conversion behavior is only possible with "build-in numeric conversions" as far as I see.
Besides, it looks like unchecked conversion is evil, comsidering the strange results.
I think this can be done with a preprocessor directive. Just like you can say:
#if DEBUG
Console.WriteLine("This code is only compiled in debug mode");
#else
Console.WriteLine("This code is only compiled in release mode");
#endif
you could say:
#if CHECKED
// code here to be compiled only if "checked" is the default overflow checking context
#else
// code for "unchecked"
#endif
But see /define (C# Compiler Options) for details on how to define such a symbol. It can be defined in the .csproj
file.
Important: This approach is only useful to distinguish the situation where you change the global default overflow checking context, from the situation where you don't. There's no way you can tell if your explicit operator
method was called from another method that used the checked
/unchecked
keyword, because as others have said, that checked
/unchecked
keyword is no longer in effect when control enters your method. At the entry of a method, the default overload checking context, as specified by compiler options or execution environment configuration, is in effect, and that's the context I'm suggesting you could detect with the preprocessor directive.
精彩评论