Cast to a reflected Type in C#

后端 未结 3 817
感情败类
感情败类 2021-01-31 05:15

Consider the following code:

object objFoo = MakeFoo(); // object MakeFoo(){return new Foo();}
MethodInfo methodInfo = typeof(Program).GetMethod(\"Baz\"); // Fo         


        
相关标签:
3条回答
  • 2021-01-31 05:28

    This is the first result in google about Casting to a reflected type.

    So for reference, in case sb wonders what would be a general way of casting to a reflected type:

    public static class ObjectExtensions
    {
        public static T CastTo<T>(this object o) => (T)o;
    
        public static dynamic CastToReflected(this object o, Type type)
        {
            var methodInfo = typeof(ObjectExtensions).GetMethod(nameof(CastTo), BindingFlags.Static | BindingFlags.Public);
            var genericArguments = new[] { type };
            var genericMethodInfo = methodInfo?.MakeGenericMethod(genericArguments);
            return genericMethodInfo?.Invoke(null, new[] { o });
        }
    }
    
    0 讨论(0)
  • 2021-01-31 05:35

    This would be equivalent to:

    object objFoo = MakeFoo();
    Foo result = (Foo)objFoo;
    

    There's no real point in casting an object to a type that's unknown at compile time - you won't be able to use it:

    object objFoo = MakeFoo();
    UnkownType result = (UknownType)objFoo;
    

    Since you don't know what UknownType is, you won't be able to use any of its methods without resorting to reflection, or to dynamics.

    0 讨论(0)
  • 2021-01-31 05:37

    No :-)

    Case 1:

    object objFoo = MakeFoo(); // object MakeFoo(){return new Foo();}
    Foo result = (Foo)objFoo;
    

    There is no reflection here, because you know the Foo type at compile time.

    Case 2: interfaces. Normally the best one... You don't know what exactly MakeFoo returns, but you know it's an IFoo interface...

    object objFoo = MakeFoo(); // object MakeFoo(){return new Foo();}
    IFoo result = (IFoo)objFoo;
    

    Case 3: you aren't sure MakeFoo returns Foo

    object objFoo = MakeFoo(); // object MakeFoo(){return new Foo();}
    
    if (objFoo is Foo)
    {
        Foo result = (Foo)objFoo;
    }
    

    or, similar

    object objFoo = MakeFoo(); // object MakeFoo(){return new Foo();}
    
    Foo foo = objFoo as Foo;
    
    if (foo != null)
    {
        // use foo
    }
    

    Case 4: type Foo is completely unknown to your program. You don't have a Foo class referenceable...

    object objFoo = MakeFoo(); // object MakeFoo(){return new Foo();}
    Type typeFoo = objFoo.GetType(); // You should check for null values before!
    
    // and now?
    
    dynamic foo = objFoo;
    
    // because you know that foo can Quack(1, 2, 3)!
    string result = foo.Quack(1, 2, 3); 
    
    // note that it will explode with a RuntimeBinderException if there is no 
    // string Quack(int, int, int) method!
    

    the dynamic internally uses reflection. You could use reflection directly to get the Quack method and call it

    Case 5: as case 4, but using directly reflection:

    object objFoo = MakeFoo(); // object MakeFoo(){return new Foo();}
    Type typeFoo = objFoo.GetType(); // You should check for null values before!
    MethodInfo mi = type.GetMethod("Quack"); // You should check if the Quack method
                                             // exists
    string result = (string)mi.Invoke(objFoo, new object[] { 1, 2, 3 });
    

    or, with some sanity checks, if you aren't sure foo can Quack correctly:

    MethodInfo mi = type.GetMethod("Quack", 
                        BindingFlags.Instance | BindingFlags.Public, 
                        null, 
                        new[] { typeof(int), typeof(int), typeof(int) }, 
                        null);
    
    if (mi != null && typeof(string).IsAssignableFrom(mi.ReturnType))
    {
        string result = (string)mi.Invoke(objFoo, new object[] { 1, 2, 3 });
    }
    

    Case -Infinity: type Foo is completely unknown to your program. You don't have a Foo class referenceable. You don't have an IFoo interface. You don't even know what a Foo is, you know only that it's a class (or perhaps it's a boxed struct, but it doesn't change from your point of view... It can't be an interface because in the end there must always be a concrete class/struct behind every interface). You don't know of its methods, its fields, its properties (because you don't know what Foo is).

    Even if you can cast an object to this unknown class, what can you do? You can't have methods in your code that accept it as a parameter/return value, because if somewhere you had:

    int INeedFoo(Foo par) { return 0; }
    

    then clearly you would know of Foo. The .NET library can't have methods that accept it as a parameter/return value, because if it had, you would know of Foo.

    The only thing you can do is pass it to some other methods that you discover through reflection that accept Foo as a parameter... But the Invoke method accepts an array of object as parameters... You don't need to cast your object to call Invoke! You only need to put it in the array.

    0 讨论(0)
提交回复
热议问题