Note: This is not a duplicate of "Use of IsAssignableFrom and “is” keyword in C#". That other question asks about
typeof(T).IsAssignableFrom(type)), wheretypeis not anobjectbut aType.This seems trivial — I can hear you saying, "Just call
x.GetType()!" — but due to the COM-related corner case mentioned below, that call causes problems, which is why I'm asking about the rewrite.
… or are there rare special cases where the two might give different results?
I stumbled upon a type check of the form:
typeof(TValue).IsAssignableFrom(value.GetType())
where TValue is a generic type parameter (without any constraints) and value is an object.
I am not entirely sure whether it is safe to rewrite the above simply as:
value is TValue
To my current knowledge, the two tests are equivalent with the exception of COM objects. is should trigger a proper QueryInterface, while IsAssignableFrom might get confused by the __ComObject RCW wrapper type and report a false negative.
Are there any other differences between is and the shown use of IsAssignableFrom?
There are more cases where
isandIsAssignableFromreturns different results, not just the one you mentioned for COM objects. For pair of array types with elements of type ElementType1 and ElementType2, where underlaying types of both element types are integer types of the same size but with opposite signedness, thentypeof(ElementType1[]).IsAssignableFrom(typeof(ElementType2[]))returns true butnew ElementType2[0] is ElementType1[]returns falseSpecifically this includes arrays with these pairs of their element types:
byte / sbyte, short / ushort, int / uint, long / ulong
IntPtr / UIntPtr
any combination of enum type and either integer type or another enum type as long as underlaying types are of the same size
any combination of IntPtr / UIntPtr / int / uint in 32-bit process
any combination of IntPtr / UIntPtr / long / ulong in 64-bit process
This is due to differences in type system of C# and CLR as explained in
Different results of
isandIsAssignableFromin all cases mentioned above results from the fact that fornew ElementType2[0] is ElementType1[]C# compiler simply emitsFalseat compile-time (because it sees no way that for example int[] can be cast to uint[] as these are completly different types from C# perspective), completly omitting any runtime type checks. Fortunately casting array to object((object)new ElementType2[0]) is ElementType1[]forces compiler to emitisinstIL instruction, which performs runtime type-check, that returns results consistent withIsAssignableFrom. This is also true for cases where target type is generic parameter, because it's type is not known at compile-time and C# compiler must emitisinst. So if you intend to replaceIsAssignableFrombyisonly in places where target type is generic parameter (as suggested in question title), I believe that these differences does not metter for you.