casting - C# - is operator - Check castability for all conversions available -


edited after reading further, modified question more specific.

as per microsoft documentation:

an expression evaluates true if provided expression non-null, , provided object can cast provided type without causing exception thrown. otherwise, expression evaluates false.

here issue below.

var test = (int32)(int16)1; // non-null , not cause exception. var test2 = (int16)1 int32; // evaluates false. 

the documentation states:

note operator considers reference conversions, boxing conversions, , unboxing conversions. other conversions, such user-defined conversions, not considered.

so, i'd assume doesn't work above because user-defined conversion.

how check see if castable type including non-reference/boxing/unboxing conversions?

note: found issue when writing unit tests casttoordefault extension works on types, including non-reference types (as compared as).


refactored answer based on mike precup's linked code

i cleaned answer because felt written in old style. plus, though slower, felt kinda wonky have table many repeated values, when each list subset of list. so, made table recursive instead. note: throwifnull throws argumentnullexception if value null.

private static readonly dictionary<type, ienumerable<type>> primitivetypetable = new dictionary<type, ienumerable<type>> {     { typeof(decimal), new[] { typeof(long), typeof(ulong) } },     { typeof(double), new[] { typeof(float) } },     { typeof(float), new[] { typeof(long), typeof(ulong) } },     { typeof(ulong), new[] { typeof(uint) } },     { typeof(long), new[] { typeof(int), typeof(uint) } },     { typeof(uint), new[] { typeof(byte), typeof(ushort) } },     { typeof(int), new[] { typeof(sbyte), typeof(short), typeof(ushort) } },     { typeof(ushort), new[] { typeof(byte), typeof(char) } },     { typeof(short), new[] { typeof(byte) } } };  private static bool isprimitivecastableto(this type fromtype, type totype) {     var keytypes = new queue<type>(new[] { totype });     while (keytypes.any())     {         var key = keytypes.dequeue();         if (key == fromtype) { return true; }         if (primitivetypetable.containskey(key)) { primitivetypetable[key].tolist().foreach(keytypes.enqueue); }     }     return false; }  /// <summary> /// determines if type castable totype. /// method more is-operator , /// allows primitives , implicit/explicit conversions compared properly. /// http://stackoverflow.com/a/18256885/294804 /// </summary> /// <param name="fromtype">the type cast from.</param> /// <param name="totype">the type casted to.</param> /// <returns>true if fromtype can casted totype. false otherwise.</returns> /// <exception cref="argumentnullexception">thrown if either type null.</exception> public static bool iscastableto(this type fromtype, type totype) {     // http://stackoverflow.com/a/10416231/294804     return totype.throwifnull().isassignablefrom(fromtype.throwifnull()) ||         fromtype.isprimitivecastableto(totype) ||         fromtype.getmethods(bindingflags.public | bindingflags.static).any(m =>                 m.returntype == totype && m.name == "op_implicit" || m.name == "op_explicit"); } 

also msdn page linked:

note operator considers reference conversions, boxing conversions, , unboxing conversions. other conversions, such user-defined conversions, not considered.

since implicit cast defined int16 , int32 types isn't reference conversion, boxing conversion, or unboxing conversion, is evaluates false.

if you're wondering why isn't reference conversion, note following page on implicit reference conversions:

reference conversions, implicit or explicit, never change referential identity of object being converted. in other words, while reference conversion may change type of reference, never changes type or value of object being referred to.

since type being changed, , it's not cast superclass, it's not considered reference conversion.

edit: answer second question edited in, view this page. i'll copy code reference:

static class typeextensions {      static dictionary<type, list<type>> dict = new dictionary<type, list<type>>() {         { typeof(decimal), new list<type> { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(char) } },         { typeof(double), new list<type> { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(char), typeof(float) } },         { typeof(float), new list<type> { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(char) } },         { typeof(ulong), new list<type> { typeof(byte), typeof(ushort), typeof(uint), typeof(char) } },         { typeof(long), new list<type> { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(char) } },         { typeof(uint), new list<type> { typeof(byte), typeof(ushort), typeof(char) } },         { typeof(int), new list<type> { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(char) } },         { typeof(ushort), new list<type> { typeof(byte), typeof(char) } },         { typeof(short), new list<type> { typeof(byte) } }     };     public static bool iscastableto(this type from, type to) {          if (to.isassignablefrom(from)) {              return true;          }         if (dict.containskey(to) && dict[to].contains(from)) {             return true;         }         bool castable = from.getmethods(bindingflags.public | bindingflags.static)                          .any(                              m => m.returntype == &&                               m.name == "op_implicit" ||                               m.name == "op_explicit"                          );          return castable;      }  }  

the code uses reflection check if implicit or explicit casts exist. reflection method doesn't work on primitives, though, check must done manually, hence dictionary possible casts primitives.


Comments

Popular posts from this blog

c# - Send Image in Json : 400 Bad request -

jquery - Fancybox - apply a function to several elements -

An easy way to program an Android keyboard layout app -