23

I have a class Thing that is implicitly castable from a string. When I call a method with a Thing parameter directly the cast from string to Thing is done correctly.

However if I use reflection to call the same method it throws the exception

System.ArgumentException : Object of type 'System.String' cannot be 
converted to type 'Things.Program+Thing'.

Maybe there is a good reason for this, but I can't figure it out. Does somebody have an idea how to get this working using reflection?

namespace Things
{
    class Program
    {
        public class Thing
        {
            public string Some;

            public static implicit operator Thing(string s)
            {
                return new Thing {Some = s};
            }
        }

        public void showThing(Thing t)
        {
            Console.WriteLine("Some = " + t.Some);
        }

        public void Main()
        {
            showThing("foo");
            MethodInfo showThingReflected = GetType().GetMethod("showThing");
            showThingReflected.Invoke(this, new dynamic[] {"foo"});
        }
    }
}

Meta: Please, no discussions why implicit casting or reflection is bad.

denfromufa
  • 5,610
  • 13
  • 81
  • 138
Dio F
  • 2,458
  • 1
  • 22
  • 39
  • 4
    Off the top of my head, I would wager it's because (I think, and correct me if I'm wrong) that implicit casting is syntax-sugar for the compiler. That the actual calls to the casting method is wired up at compile-time. EDIT: Do you need to have some generic way of invoking the implicit converter for any object conversion? Or is this a special case that you'd be willing to target a separate static method or some other reflection call to a predetermined method or perhaps a specialized constructor? – Chris Sinclair Jul 18 '12 at 14:48
  • similar question [here](http://stackoverflow.com/questions/4501469/c-sharp-implicit-cast-overloading-and-reflection-problem) – James Jul 18 '12 at 14:54
  • 2
    Implicit casting is impossible via reflection but you can use [TypeConvertor](http://msdn.microsoft.com/en-us/library/98bbex99.aspx#the_typeconverter_class). – Saeed Amiri Jul 18 '12 at 14:58
  • If you really wanted to do this, you could construct an expression tree that does what you need and then compile it to a method and execute it. If you feel that works for you, I can add that as an answer. – Ani Jul 18 '12 at 15:08
  • @ChrisSinclair: Actually I use a third party application which performs the reflection stuff. But I guess i can somehow wrap it. – Dio F Jul 18 '12 at 15:16
  • @SaeedAmiri: As far as I see TypeConverter does no implicit conversion, doesn't it? – Dio F Jul 18 '12 at 15:19
  • Can't you just state the conversion explicitly, i.e. `(Thing)"foo"`, when you use reflection? – Jeppe Stig Nielsen Jul 18 '12 at 15:34
  • possible duplicate of [How do I perform explicit operation casting from reflection?](http://stackoverflow.com/questions/7351289/how-do-i-perform-explicit-operation-casting-from-reflection) – nawfal Aug 12 '14 at 06:50

3 Answers3

17

The trick is to realize that the compiler creates a special static method called op_Implicit for your implicit conversion operator.

object arg = "foo";

// Program.showThing(Thing t)
var showThingReflected = GetType().GetMethod("showThing");

// typeof(Thing)
var paramType = showThingReflected.GetParameters()
                                  .Single()
                                  .ParameterType; 

// Thing.implicit operator Thing(string s)
var converter = paramType.GetMethod("op_Implicit", new[] { arg.GetType() });

if (converter != null)
    arg = converter.Invoke(null, new[] { arg }); // Converter exists: arg = (Thing)"foo";

// showThing(arg)
showThingReflected.Invoke(this, new[] { arg });
Ani
  • 111,048
  • 26
  • 262
  • 307
5

Found an answer which uses a TypeConverter (as Saeed mentions)
Seems to do the job.

TypeConverter For Implicit Conversion when using reflection

AlanT
  • 3,627
  • 20
  • 28
1

In this specific case you can make the conversion through the array type, that is

showThingReflected.Invoke(this, new Thing[] {"foo"});

but that's a kind of "cheating". In general, you cannot expect the Invoke to consider your user-defined implicit operator. This conversion must be inferred compile-time.

Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181