Is it possible to use implicit casts with types created at run-time in c#?

633 Views Asked by At

I'm creating a type at runtime using Reflection.Emit. The problem is that whenever I instantiate an instance of the new type I have to use object or dynamic because the type isn't known at compile time. This works fine except for when I would want another type to implicitly cast to the new type during assignment. The variable happily takes on the new value and it's corresponding type without attempting to cast to its current type.

Is there any way to create a variable of a newly created type that will allow for implicit casting? I'm perfectly happy to give up compile-time checking but I would like these casts to at least be attempted at run-time.

Edit:

Here is an example to make it more clear. This is what happens when you know the type at compile-time:

MyClass a;
//this calls the implicit cast operator and 'a' stays of the same type
a = 5;

and this is what happens if you don't:

Type t = CreateTypeUsingTypeBuilder();
object a = Activator.CreateInstance(t);
//this does not call the implicit cast operator and 'a' just becomes in integer
a = 5;

Also, I'm not surprised at this behavior or asking why it happens. I'm asking if there is any sort of workaround to achieve the desired behavior of having it check for an implicit operator at run-time.

2

There are 2 best solutions below

0
On

If the idea is, as I suppose in this context, to create wrapper classes for known types in runtime, then I have a few ideas you could try.

One is to add a parameterized constructor in the wrapper type, that takes an object of the wrapped type as the parameter and then uses that object to initialize the wrapper object (like you would do in an implicit conversion operator). Then, knowing that you can use e.g. an integer as a constructor parameter, you could simply do this:

Type t = CreateTypeUsingTypeBuilder();
object a = Activator.CreateInstance(t, 5);

This will search the type for a constructor that could be invoked with the given object. You might get MissingMethodException if no matching public constructor is found.

Another idea is to create either an interface or an abstract base type for your types built in runtime, that requires the derived classes to implement some sort of conversion method. When you derive your built types from this abstract class or make them implement the interface, you can cast the object created with the Activator to that class or that interface and then call the conversion method already normally. If you make your interface generic, you could have multiple different conversion implementations.

public interface IMyWrapper<T>
{
    IMyWrapper<T> Convert(T value);
}

While there is no way to use an implicit operator implicitly, I think you could achieve your ultimate goal of converting an integer to your built type in some other way, including one or the other hinted above.

2
On

In order to understand why this is not possible, at least not directly, one needs to understand how implicit conversion operators work in the first place.

When you write something like this

MyNumericType x = new MyNumericType(123);
double y = x;

the compiler realizes that x and y are of different types, and searches MyNumericType to see if there is an implicit conversion operator defined:

public static implicit operator double(MyNumericType n) {
    return n.doubleValue;
}

Once the operator is found, the compiler invokes it as if it were a regular static method (which it is).

When you work with types generated at runtime, you should generate the conversion at runtime as well. For example, if you do this

private static Func<object,object> MakeConverter(Type t1, Type t2) {
    var p = Expression.Parameter*(typeof(object));
    var eFrom = Expression.Convert(p, t1);
    var eTo = Expression.Convert(eFrom, t2);
    var res = Expression.Convert(eTo, typeof(object));
    var lambda = Expression.Lambda<Func<object,object>>(res, new[] { p });
    return (Func<object,object>)lambda.Compile();
}

With this method in place you can do this:

Type runtimeType1 = ...
Type runtimeType2 = ...
var converter = MakeConverter(runtimeType1, runtimeType2);
object objRuntimeType1 = ...
object objRuntimeType2 = converter(objRuntimeType1);