Reputation: 953
Alright, I've been trying to find any information on this for a while. I built a small class to see how hard type-safe-enums are to implement for strings, because I want to use them for database field-names and such. I've never liked the fact that enums could only be used for integers.
However, even though I have implemented an implicit operator
for this class, every time I try to use it, it gives me an invalid cast exception. I'm at a loss, as I can see nothing wrong with my code at this point.
Here's the class:
/// <summary>
/// SBool - type-safe-enum for boolean strings
/// </summary>
public sealed class SBool
{
private readonly String name;
private readonly int value;
// these guys were for conversions. They might work better in another case,
// but for this one, they weren't very helpful.
// ((I.e. they didn't work either.))
//private static readonly Dictionary<SBool, String> stringsByBool = new Dictionary<SBool, String>();
//private static readonly Dictionary<String, SBool> boolsByString = new Dictionary<String, SBool>();
public static readonly SBool True = new SBool( 1, "true" );
public static readonly SBool False = new SBool( 0, "false" );
private SBool( int value, String name )
{
this.name = name;
this.value = value;
//stringsByBool[this] = name;
//boolsByString[name] = this;
}
private SBool( SBool sbool )
{
this.name = sbool.name;
this.value = sbool.value;
//stringsByBool[this] = name;
//boolsByString[name] = this;
}
public override String ToString()
{
return name;
}
/// <summary>
/// allows implicit casting of SBools to strings
/// </summary>
/// <param name="sbool">the SBool to cast into a string</param>
/// <returns>the string equivalent of the SBool (its value)</returns>
public static implicit operator String( SBool sbool )
{
if ( sbool == SBool.True )
return SBool.True.name;
else
return SBool.False.name;
}
/// <summary>
/// implicitly cast a string into a SBool.
/// </summary>
/// <param name="str">the string to attempt to cast as a SBool</param>
/// <returns>the SBool equivalent of the string,
/// SBool.False if not either "true" or "false".</returns>
public static explicit operator SBool( String str )
{
if ( !String.IsNullOrEmpty(str) && str.ToLower() == "true" )
return SBool.True;
else
return SBool.False;
}
public static bool operator ==( SBool left, SBool right )
{
return left.value == right.value;
}
public static bool operator !=( SBool left, SBool right )
{
return left.value != right.value;
}
}
This is failing on the check of a Session variable:
if( ( (string)Session["variable"] ) == SBool.False )
with an InvalidCastException,
and I quite frankly have no idea why.
Thanks in advance; cookies for anyone who can explain why this doesn't work (cookies not available in all areas). I'm going to get other things fixed, but let me know if there's anything that is unclear. For more info on Type-Safe enums, here's one of the SO posts I based this class off of.
[MetaEDIT] disregard this. I was horribly, horribly mistaken. [/edit]
Upvotes: 11
Views: 4443
Reputation: 1796
As Servy mentioned these types of cast happen at compile time. However there is a way to force this check to occur at runtime by using dynamic keyword. Instead of casting to SBool cast to dynamic. This will cause cast operators to be executed at run time.
In my opinion casting to SBool is a cleaner and less error prone solution.
Upvotes: 1
Reputation: 203827
User defined implicit and explicit operators are entirely a compile time mechanism, not a runtime mechanism. Once the code is compiled the runtime has no idea about any user defined conversion operators.
When the compiler is doing it's type checking and sees that a Foo
is expected but the actual value is a Bar
it will first check through the built in language implicit conversion operators to see if an appropriate conversion exists. If it doesn't, it checks through the definition of both Foo
and Bar
for implicit conversion operators, if it finds one it will add in a call to the relevant static method to perform the conversion. Once you get to runtime only the built in language implicit operators will be applied.
In this case you aren't converting from SBool
to a string
, you're converting from object
to string
(as far as the compiler is concerned) and there is no conversion operator to handle that.
You need to first cast the result of the Session
variable to SBool
(which is what it really is) and then to some other type in order to be able to leverage the user defined conversion operators. So:
if( ( (SBool)Session["variable"] ) == SBool.False )
will work just fine.
Upvotes: 12
Reputation: 2557
Wen you're casting Session[] to a string, you're performing an explicit conversion. You don't have a SBool->String explicit operator defined, only implicit.
You need to add an explicit SBool->string conversion.
Upvotes: -1