Suppose I have a generic method:
T Foo(T x) {
return x;
}
So far so good. But I want to do something special if it's a Hashtable. (I know this is a completely contrived example. Foo() isn't a very exciting method, either. Play along.)
if (typeof(T) == typeof(Hashtable)) {
var h = ((Hashtable)x); // CS0030: Cannot convert type 'T' to 'System.Collections.Hashtable'
}
Darn. To be fair, though, I can't actually tell if this should be legal C# or not. Well, what if I try doing it a different way?
if (typeof(T) == typeof(Hashtable)) {
var h = x as Hashtable; // works (and no, h isn't null)
}
That's a little weird. According to MSDN, expression as Type is (except for evaluating expression twice) the same as expression is type ? (type)expression : (type)null.
What happens if I try to use the equivalent expression from the docs?
if (typeof(T) == typeof(Hashtable)) {
var h = (x is Hashtable ? (Hashtable)x : (Hashtable)null); // CS0030: Cannot convert type 'T' to 'System.Collections.Hashtable'
}
The only documented difference between casting and as that I see is "the as operator only performs reference conversions and boxing conversions". Maybe I need to tell it I'm using a reference type?
T Foo(T x) where T : class {
var h = ((Hashtable)x); // CS0030: Cannot convert type 'T' to 'System.Collections.Hashtable'
return x;
}
What's going on? Why does as work fine, while casting won't even compile? Should the cast work, or should the as not work, or is there some other language difference between casting and as that isn't in these MSDN docs I found?
Ben's answer basically hits the nail on the head, but to expand on that a bit:
The problem here is that people have a natural expectation that a generic method will do the same thing that the equivalent non-generic method would do if given the types at compile time. In your particular case, people would expect that if T is short, then (int)t should do the right thing -- turn the short into an int. And (double)t should turn the short into a double. And if T is byte, then (int)t should turn the byte into an int, and (double)t should turn the byte into a double... and now perhaps you begin to see the problem. The generic code we'd have to generate would basically have to start the compiler again at runtime and do a full type analysis, and then dynamically generate the code to do the conversion as expected.
That is potentially expensive; we added that feature in C# 4 and if that's what you really want, you can mark the objects as being of type "dynamic" and a little stripped-down version of the compiler will start up again at runtime and do the conversion logic for you.
But that expensive thing is typically not what people want.
The "as" logic is far less complicated than the cast logic because it does not have to deal with any conversions other than boxing, unboxing and reference conversions. It does not have to deal with user-defined conversions, it does not have to deal with fancy representation-changing conversions like "byte to double" that turn one-byte data structures into eight-byte data structures, and so on.
That's why "as" is allowed in generic code but casts are not.
All that said: you are almost certainly doing it wrong. If you have to do a type test in generic code your code is not generic. This is a really bad code smell.
The cast operator in C# can:
box/unbox
upcast/downcast
call a user-defined conversion operator
as Hashtable always means the second.
By eliminating value types with the constraint, you've knocked out option 1, but it's still ambiguous.
Here are the two "best" approaches that both work:
Hashtable h = x as Hashtable;
if (h != null) {
...
}
or
if (x is Hashtable) {
Hashtable h = (Hashtable)(object)x;
...
}
The first needs only one type test, so it's very efficient. And the JIT optimizer recognizes the second one, and treats it like the first (at least when dealing with non-generic types, I'm not sure about this particular case.)
"The C# compiler only lets you implicitly cast generic type parameters to Object, or to constraint-specified types, as shown in Code block 5. Such implicit casting is type safe because any incompatibility is discovered at compile-time."
See the section on Generics and Casting:
http://msdn.microsoft.com/en-us/library/ms379564(v=vs.80).aspx#csharp_generics_topic5
Related
Why is this a compile time error?
public TCastTo CastMe<TSource, TCastTo>(TSource i)
{
return (TCastTo)i;
}
Error:
Cannot convert type 'TSource' to 'TCastTo'
And why is this a runtime error?
public TCastTo CastMe<TSource, TCastTo>(TSource i)
{
return (TCastTo)(object)i;
}
int a = 4;
long b = CastMe<int, long>(a); // InvalidCastException
// this contrived example works
int aa = 4;
int bb = CastMe<int, int>(aa);
// this also works, the problem is limited to value types
string s = "foo";
object o = CastMe<string, object>(s);
I've searched SO and the internet for an answer to this and found lots of explanations on similar generic related casting issues, but I can't find anything on this particular simple case.
Why is this a compile time error?
The problem is that every possible combination of value types has different rules for what a cast means. Casting a 64 bit double to a 16 bit int is completely different code from casting a decimal to a float, and so on. The number of possibilities is enormous. So think like the compiler. What code is the compiler supposed to generate for your program?
The compiler would have to generate code that starts the compiler again at runtime, does a fresh analysis of the types, and dynamically emits the appropriate code.
That seems like perhaps more work and less performance than you expected to get with generics, so we simply outlaw it. If what you really want is for the compiler to start up again and do an analysis of the types, use "dynamic" in C# 4; that's what it does.
And why is this a runtime error?
Same reason.
A boxed int may only be unboxed to int (or int?), for the same reason as above; if the CLR tried to do every possible conversion from a boxed value type to every other possible value type then essentially it has to run a compiler again at runtime. That would be unexpectedly slow.
So why is it not an error for reference types?
Because every reference type conversion is the same as every other reference type conversion: you interrogate the object to see if it is derived from or identical to the desired type. If it's not, you throw an exception (if doing a cast) or result in null/false (if using the "as/is" operators). The rules are consistent for reference types in a way that they are not for value types. Remember reference types know their own type. Value types do not; with value types, the variable doing the storage is the only thing that knows the type semantics that apply to those bits. Value types contain their values and no additional information. Reference types contain their values plus lots of extra data.
For more information see my article on the subject:
http://ericlippert.com/2009/03/03/representation-and-identity/
C# uses one cast syntax for multiple different underlying operations:
upcast
downcast
boxing
unboxing
numeric conversion
user-defined conversion
In generic context, the compiler has no way of knowing which of those is correct, and they all generate different MSIL, so it bails out.
By writing return (TCastTo)(object)i; instead, you force the compiler to do an upcast to object, followed by a downcast to TCastTo. The compiler will generate code, but if that wasn't the right way to convert the types in question, you'll get a runtime error.
Code Sample:
public static class DefaultConverter<TInput, TOutput>
{
private static Converter<TInput, TOutput> cached;
static DefaultConverter()
{
ParameterExpression p = Expression.Parameter(typeof(TSource));
cached = Expression.Lambda<Converter<TSource, TCastTo>(Expression.Convert(p, typeof(TCastTo), p).Compile();
}
public static Converter<TInput, TOutput> Instance { return cached; }
}
public static class DefaultConverter<TOutput>
{
public static TOutput ConvertBen<TInput>(TInput from) { return DefaultConverter<TInput, TOutput>.Instance.Invoke(from); }
public static TOutput ConvertEric(dynamic from) { return from; }
}
Eric's way sure is shorter, but I think mine should be faster.
The compile error is caused because TSource cannot be implicitly cast to TCastTo. The two types may share a branch on their inheritance tree, but there is no guarantee. If you wanted to call only types that did share an ancestor, you should modify the CastMe() signature to use the ancestor type instead of generics.
The runtime error example avoids the error in your first example by first casting the TSource i to an object, something all objects in C# derive from. While the compiler doesn't complain (because object -> something that derives from it, could be valid), the behaviour of casting via (Type)variable syntax will throw if the cast is invalid. (The same problem that the compiler prevented from happening in example 1).
Another solution, which does something similar to what you're looking for...
public static T2 CastTo<T, T2>(T input, Func<T, T2> convert)
{
return convert(input);
}
You'd call it like this.
int a = 314;
long b = CastTo(a, i=>(long)i);
Hopefully this helps.
If I have this code, this will compile and work as it should:
class MyNumber // Just a class.
{
static public explicit operator MyNumber(byte b)
{
return new MyNumber();
}
}
Decimal d = new Decimal();
MyNumber c1 = (MyNumber)d;
Perhapse some people are a bit of a surprise, since there is no existing explicit cast from a decimal to MyNumber. But since there is a explicit cast from decimal to byte and there is also a explicit cast from a byte to MyNumber, the compiler is kind enough to insert that extra explicit cast for me.
In short: If the programmer uses an explicit cast, the compiler takes the freedom to search for other explicit cast to get the whole thing going.
So... I tried the same thing with my own classes. Instead of byte and decimal, I used MyByte and Mydecimal. The code looks like this:
class MyDecimal // Simulates a decimal.
{
static public explicit operator MyByte(MyDecimal a) // Just like in a decimal.
{
return new MyByte();
}
}
class MyByte // Simulates a byte.
{
}
class MyNumber // Just a class.
{
static public explicit operator MyNumber(MyByte b)
{
return new MyNumber();
}
}
MyDecimal d = new MyDecimal();
MyNumber c2 = (MyNumber)d; // <== Will not compile!
The last line will not compile. It gives the error: "Cannot convert type 'DoubleExplicitCasts.Program.MyDecimal' to 'DoubleExplicitCasts.Program.MyNumber'". Well... why not???
So my question is: Why do the explicit operators inside .NET system get a special treatment and my user explicit operators do not?
EDIT
I know this code is not functional and values are not transfered from one instance to another, but that is beside the point.
IMO, that would lead to "happy debugging" and really, really complicated and non-obvious code.
Just imagine 3 or more levels of such user-defined conversions, and how would you search for error, caused by conversion in the middle (e.g such conversion was introduced by mistake or not supposed to be used in that situation).
Thanks God such behaviour is not supported.
Well, trivially, because that's how it's defined by the C# standard.
From section 6.4.3:
Evaluation of a user-defined conversion never involves more than one user-defined or lifted conversion operator. In other words, a conversion from type S to type T will never first execute a user-defined conversion from S to X and then execute a user-defined conversion from X to T.
As to why they chose to limit the conversions in that way - that's a different matter. I'm going to propose two possible reasons:
It would allow the possibility of too many "surprising" conversions
It would make the compilation process too slow (possible combinational explosion)
but that's just conjecture on my part.
Expression.Convert generally throws in InvalidOperationException when "No conversion operator is defined between expression.Type and type."
The return type parameter of Func<> is covariant for reference types.
// This works.
Func<SomeType> a = () => new SomeType();
Func<object> b = a;
It isn't covariant for value types.
Variance applies only to reference types; if you specify a value type for a variant type parameter, that type parameter is invariant for the resulting constructed type.
// This doesn't work!
Func<int> five = () => 5;
Func<object> fiveCovariant = five;
However, Expression.Convert believes it is possible.
Func<int> answer = () => 42;
Expression answerExpression = Expression.Constant( answer );
// No InvalidOperationException is thrown at this line.
Expression converted
= Expression.Convert( answerExpression, typeof( Func<object> ) );
No InvalidOperationException is thrown when calling Expression.Convert. The expression tree compiles correctly, but when I call the created delegate, I get an expected InvalidCastException.
Is this a bug? (I reported it as a bug on Microsoft Connect.)
How to properly check whether a type can be converted to another type? Some answers seem to refer to using Convert. I would very much prefer a method which doesn't have to use exception handling as logic.
It seems the entire variance logic isn't properly supported. It correctly complains about not being able to convert from Func<SomeType> to Func<SomeOtherType>, but it doesn't complain about converting from Func<object> to Func<string>.
Interestingly, once SomeType and SomeOtherType are in the same class hierarchy (SomeOtherType extends from SomeType), it never throws the exception. If they aren't, it does.
Is this a bug?
Yes. The expression tree library was probably not updated consistently throughout when we added covariance and contravariance. Sorry about that.
I reported it as a bug on Microsoft Connect.
Thanks! Someone will have a look at it then.
How to properly check whether a type can be converted to another type?
The question is vague. Given two type objects, do you want to know:
Does the .NET runtime think the types are assignment compatible?
Does the C# compiler think that there is an implicit conversion between the types?
Does the C# compiler think that there is an explicit conversion between the types?
"int" and "short" for example are not assignment compatible by .NET rules. Int is explicitly convertible but not implicitly convertible to short, and short is both implicitly and explicitly convertible to int, by C# rules.
It's not a bug. Expression.Convert represents a run-time type check, so an InvalidCastException at run time would be the expected behavior.
Edit: that's not entirely correct. It doesn't exactly represent a run-time type check (Here's the documentation: http://msdn.microsoft.com/en-us/library/bb292051.aspx). However, the expression tree is created at run-time, so all the type checking must happen then.
Edit: I'm using .NET 4.0 too.
By the way, Convert doesn't complain about converting from Func<object> to Func<string> because that conversion is sometimes legal. It is legal if the Func<object> is a covariant reference to an object whose runtime type is Func<string>. Example:
Func<string> sFunc = () => "S";
Func<object> oFunc = sFunc;
Func<string> anotherSFunc = (Func<string>)oFunc;
Now, Convert decides whether to throw an InvalidOperationException by checking whether one type can be coerced to another. When checking delegates for a potential reference conversion, it looks like the code does check contravariant (argument) parameters and throws an InvalidOperationException if any is a value type. It doesn't seem to do that check for the covariant (return type) parameter. So I am beginning to suspect that this is a bug, though I'm inclined to reserve judgment on that until I have a chance to look at the spec (see Eric Lippert's Maybe there's something wrong with the universe, but probably not), which I don't have time to do right now.
Eric Lippert answered part 1 of my question: it seems to be a bug. I started looking for a solution to question 2:
How to properly check whether a type can be converted to another type?
I just commit a first attempt at a Type.CanConvertTo( Type to ) method to my library. (Sources are way too complex to post here, sorry.)
if ( fromType.CanConvertTo( toType ) )
{
convertedExpression = Expression.Convert( expression, toType );
}
So far it supports checking implicit conversions for:
Simple non-generic types.
Variance for nested generic interfaces and delegates.
Invariance for generic value type parameters.
It doesn't support:
Type constraints.
Custom implicit conversion operators.
It passes all my tests for implicit conversions. Although you can specify to include explicit conversions as well (and I actually use it like that at the moment), I still need to write unit tests for all those scenarios.
I've encountered this a couple of times and been perplexed.
Cat c = new Cat("Fluffy");
return (Animal)c;
Cat c = new Cat("Fluffy");
return c as Animal;
What's the reason for both of these syntaxes to exist?
The as operator is a safe cast. If the types are not compatible, as will return null.
The explicit cast, (Animal)c, on the other hand, will throw an InvalidCastException if the types are not assignment-compatible.
Also worth noting that as only works for inheritance relationships, whereas the explicit cast operator will work for value types...
decimal d = 4.0m;
int i = (int)d;
...and any other explicit conversion operators defined on the type with public static explicit operator. These won't work with as.
http://blogs.msdn.com/csharpfaq/archive/2004/03/12/88420.aspx
"Using the as operator differs from a cast in C# in three important ways:
1) It returns null when the variable you are trying to convert is not of the requested type or in it's inheritance chain, instead of throwing an exception.
2) It can only be applied to reference type variables converting to reference types.
3) Using as will not perform user-defined conversions, such as implicit or explicit conversion operators, which casting syntax will do.
There are in fact two completely different operations defined in IL that handle these two keywords (the castclass and isinst instructions) - it's not just "syntactic sugar" written by C# to get this different behavior. The as operator appears to be slightly faster in v1.0 and v1.1 of Microsoft's CLR compared to casting (even in cases where there are no invalid casts which would severely lower casting's performance due to exceptions)."
With this:
return (Animal)c;
You are explicitly saying that c is of type animal, and if not something has gone wrong.
With this:
return c as Animal;
You are saying that you are pretty sure that c is of type animal, but maybe not all the time.
Eric Lippert talks about it in his blog:
http://blogs.msdn.com/ericlippert/archive/2009/10/08/what-s-the-difference-between-as-and-cast-operators.aspx
The cast syntax, return (Animal)c; will throw an InvalidCastException if the object cannot be cast to the type Animal. This is nice if you know it is an Animal, and if it is not, something has gone very wrong.
The return c as Animal; syntax will return null. This is handy if you would like to avoid catching exceptions:
Cat c = GetAnimal("Fluffy");
if (c == null)
{
AddAnimal("Fluffy");
}
Can you please explain the difference between explicit and implicit type casts?
This is a little tricky because the "cast" syntax in C# actually does a range of different things (cast, primitive convert, bespoke convert, etc)
In an implicit cast, there is an obvious reference-preserving conversion between the two:
List<int> l = new List<int>();
IList<int> il = l;
The compiler can prove that this is safe just from static analysis (List<int> is always an IList<int>)
With an explicit cast, either you are telling the compiler that you know more than it does - "please believe me, but check anyway":
List<int> l = new List<int>();
IList<int> il = l;
List<int> l2 = (List<int>)il;
Although this cast is possible, the compiler won't accept that all IList<int>s are actually List<int> - so we must tell it to let it by.
In an implicit primitive conversion (providedby the language spec), it is generally assumed that there is a safe, non-risky, non-lossy (caveat: see Jon's comment) conversion:
int i = 1;
float f = i;
With an explicit primitive conversion, it is likely that the conversion could lose data, or is non-obvious:
float f = 1;
int i = (int)f;
With bespoke operators, all bets are off, and you'd have to look at the documentation. It could be a reference-cast, or it could be anything. It may follow similar rules to primitive conversions (example: decimal), or it could do anything randomly:
XNamespace ns = "http://abc/def"; // implicit
XAttribute attrib = GetAttrib();
int i = (int)attrib; // explicit (extracts text from attrib value and
// parses to an int)
Both of these run custom code that is context-specific.
What's the difference between the President of the United States and the President of Canada?
Since there is no President of Canada, it's hard to answer the question. The right thing to do is to push back and ask for clarification of the question. By "the President of Canada", does the questioner mean the Queen (ceremonial head of state), the Governor General (who can veto bills) or the Prime Minister (who effectively acts as the executive), or something else? Hard to say without clarification.
And even with clarification, it's a vague question. What differences do you want to know about?
Since there is no such thing as an "implicit cast" in C# it is hard to answer your question. In C#, casting is an operator. So I'll push back on it.
Did you mean to ask "what's the difference between an explicit conversion and an implicit conversion?" Or did you mean to ask about the semantics of the cast operator? Or the difference between the cast operator and other type conversion operators? Or situations in which cast operators can be "implicitly" inserted into your code by the compiler? (For example, the foreach loop and the += operator can both implicitly insert an invisible cast.)
Can you clarify the question? What two things are you asking for comparison of, and what sorts of differences are you interested in?
You might consider reading the "Conversions" chapter of the C# specification. Odds are good that any question you have about conversions are answered there.
int i = 2;
float a = i; // Implicit
float b = (float)i; // Explicit
Explicit Conversions
If a conversion cannot be made without a risk of losing information then it is an explicit conversion.
For example -
class ExplicitConversions
{
static void Main()
{
int x;
double y = 6358.057;
// Cast double to int.
x = (int)y;
System.Console.WriteLine(x);
}
}
Implicit Conversions
If a conversion can be made without a risk of losing information then it is an implicit conversion. No special syntax is required because the conversion is type safe and no data is lost.
For example -
class ImplicitConversions
{
static void Main()
{
int x = 6714;
double y;
// Cast int to double.
y = x;
System.Console.WriteLine(y);
}
}
I think this post explains it best.
Explicit cast:
int x = 0;
float y = 3.8f;
x += (int) y; //Explicit cast.
This tells the compiler that the cast was intentional and that you know that the fractional part will go lost. The compiler won't complain.
Implicit cast:
int x = 0;
float y = 3.8f;
x += y; //Implicit cast
The compiler will complain because the fractional part will be lost when converting float to int.
Explicit in MSDN
Implicit in MSDN
A simple search will give lots of informations in the net.
difference between implicit and explicit type
Type Casting: Conversion of one data type to another data type. and it can be done in two ways.
Implicit Type Casting,
Explicit Type Casting
Implicit type casting is performed by the compiler on its own when it encounters a mixed data type expression in the program. it is also known as automatic conversion as it is done by the compiler without the programmer’s assistance. implicit casting doesn’t require a casting operator.
Example:-
int a=42;
float b=a;
here b will contain typecast value of a, because while assigning value to b compiler typecasts the value of an into float then assigns it to b.
Explicit type casting is performed by the programmer. In this typecasting programmer tells the compiler to typecast one data type to another data type using type casting operator. but there is some risk of information loss is there, so one needs to be careful while doing it
Example:-
float a=42.12;
int b=(int)a;
here we explicitly converted float value of a to int while assigning it to int b. (int) is the typecasting operator with the type in which you wants to convert.
Explicit from MSDN -
If a conversion operation can cause exceptions or lose information,
you should mark it explicit. This prevents the compiler from silently
invoking the conversion operation with possibly unforeseen
consequences.
Implicit from MSDN -
if the conversion is guaranteed not to cause a loss of data
From a general point of view; here is the diff between the two type of Casts :
Implicit type casting is performed by the compiler on its own when it encounters a mixed data type expression in the program. it is also known as automatic conversion as it is done by compiler without programmer’s assistance. implicit casting doesn’t require a casting operator.
Explicit type casting is performed by the programmer. In this type casting programmer tells compiler to type cast one data type to another data type using type casting operator. but there is some risk of information loss is there, so one needs to be careful while doing it.
you can refer to This article for more details.