Is there a way to do dynamic implicit type casting in C#?
Asked Answered
B

3

12

Given this class with an implicit cast operator:

public class MyDateTime
{
    public static implicit operator MyDateTime(System.Int64 encoded)
    {
        return new MyDateTime(encoded);
    }

    public MyDateTime(System.Int64 encoded)
    {
        _encoded = encoded;
    }
    System.Int64 _encoded;
}

I can now do the following:

long a = 5;
MyDateTime b = a;

But NOT the following:

long f = 5;
object g = f;
MyDateTime h = g;

This gives a compile time:

Cannot implicitly convert type 'object' to 'MyDateTime'.

Makes sense to me.

Now I modify the previous example as follows:

long f = 5;
object g = f;
MyDateTime h = (MyDateTime)g;

This compiles fine. Now I get a runtime InvalidCastException:

Unable to cast object of type 'System.Int64' to type MyDateTime'.

This tells me that C# implicit cast operators are applied at compile time only, and are not applied when the .NET runtime is attempting to dynamically cast an object to another type.

My questions:

  1. Am I correct?
  2. Is there some other way to do this?

By the way, the full application is that I'm using Delegate.DynamicInvoke() to call a function that takes a MyDateTime parameter, and the type of the argument I'm passing to DynamicInvoke is a long.

Blacklist answered 18/1, 2010 at 23:59 Comment(0)
W
14

Am I correct?

Yes, yes you are. To be nit-picky, you should be saying "user-defined implicit conversion" rather than "implicit cast" -- a cast is (almost) always explicit. But your deduction that overload resolution chooses which user-defined conversion to call at compile time and not at run time is correct.

Is there some other way to do this?

Yes. In C# 4 if you type your "object" as "dynamic" then we start up the compiler again at runtime and re-perform all the analysis on the operands as though their compile-time types were the current run-time types. As you might imagine, this is not cheap, though we are very smart about caching and re-using the results should you do this in a tight loop.

Wallsend answered 19/1, 2010 at 0:27 Comment(6)
Just out of curiosity, what are the reasons that operators don't behave more like methods at runtime? Given your answer, it feels as if they are mere syntactic sugar and not much more. In my view it would make C# even more powerful if these kind of operators are promoted as a first-class member of any type (which means they become part of all the other object-oriented goodness like inheritance, overriding and interfacing). Would leveraging these at runtime by default imply major changes to the design and implementation of the language?Penelope
@MDeSchaepmeester: You are right that there is a bit of a disconnect here. Compare the design of int to decimal for example. You can say Func<decimal, decimal> add = decimal.Add; but there is no way to do the same for int; you have to say Func<int, int> add = (x, y) => x + y. It would have been nice I think had all the built-in types been designed as Decimal was, and then the runtime or compiler could choose to lower them to more fundamental operations for performance reasons. But this sort of consistency really follows from a "functional" mindset.Wallsend
@MDeSchaepmeester: I suspect that the original designers of the runtime simply were not thinking about that sort of unifying functional abstraction when designing the type system and the operations on built-in types. And of course it is also odd that decimal has both an operator+ and an Add method. And don't even get me started on the dozen ways there are to represent the equality operation! It's a bit of a mess really. Next time you design a framework from scratch, get this stuff right early.Wallsend
@MDeSchaepmeester: Also as you note none of this stuff works well with interfaces. An often-proposed feature is to add "static interfaces" so that you could say Matrix<T> where T : IAddable<T, T> and the like. That really would require some pretty serious work on the language and the runtime, so it's never been super high on the priority list.Wallsend
@EricLippert: Jon Skeet's MiscUtil provides generic operators (e.g., Operator.Add<T> and Operator.Add<TArg1,TArg2>) in a relatively clean way. This gets you generic operators functions, but doesn't give you type safety, which is more important. However, you might be able to get similar protection via Code ContractsAtwater
Can I somehow use the dynamic implicit conversion in Expression Lambda? I have something like Expression.Lambda(delegateType, Expression.Convert(getValExpr, resType), exprParameters) but the processCallExpr results and object. Example: type from the processCall is int, resType type is double and I need some expression to convert it implicitly instead of cast error.Censorious
V
-3

I know this is an older question but in case anyone else stumbles upon the same problem, this will compile and run fine:

long f = 5;
object g = f;
MyDateTime h = g as MyDateTime;
Viafore answered 30/1, 2013 at 8:3 Comment(1)
It will run fine in the sense that it will not throw an InvalidCastException, however h will be null which is not what the OP wants or expects.Penelope
L
-4

Adding an explicit operator should work: http://msdn.microsoft.com/en-us/library/85w54y0a(VS.80).aspx

Loya answered 19/1, 2010 at 0:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.