动态对象强制转换为仅在运行时已知的类型

phi*_*ady 5 c#

情况: 仅在运行时键入baseType.objectInstance是baseType类型的子类,objectInstance是从对动态方法的调用中检索的

需要:

Type baseType = ...; // obtained at runtime
var baseDynamicInstance = (basetype) objectInstance; // or reflection cast
Run Code Online (Sandbox Code Playgroud)

硬编码时,它的工作原理

   var oi = (PartnerBase) objectInstance;   // this works
Run Code Online (Sandbox Code Playgroud)

尝试:

public object CastPocoInstance(Type targetType, object objectInstance) {
    MethodInfo castMethod = objectInstance.GetType().GetMethod("Cast").MakeGenericMethod(targetType); // <<< NULL REF here
    object castedObject = castMethod.Invoke(null, new object[] { objectInstance });
    return castedObject;
   }
Run Code Online (Sandbox Code Playgroud)

错误: null对象引用错误.
在即时窗口中,我看到objectInstance.GetType().GetMethod("Cast")返回null
objectInstance.GetType.GetMethods()//在即时窗口中显示一个列表.//没有显示强制转换方法

我看了很多例子,这对我来说是Type.GetMethod("Cast")是正确的.但它没有用.所以显然我做错了什么.

有小费吗

编辑:没有向下转换为基本硬编码的调用错误

[Microsoft.CSharp.RuntimeBinder.RuntimeBinderException] = {"The best overloaded method match for 'P42.RepositoryBase.GetEntityState(P42.Core.PartnerBase)' has some invalid arguments"}

EDIT2: AN ObjectInstance is retrieved from a dynamic method call. The object should be used in a call to a dynamic method. If I hard code down cast it works. var x = (baseobject) ObjInstance And call the dynamic method using x. it Works.

The base type is also only known at runtime. Is there a way to cast SpecificObject to BAseObject dynamically?

Cos*_*und 5

对于编译器来说,转换为仅在运行时已知的类型似乎是一种毫无意义的操作:因为根据定义,它直到运行时才知道该类型,因此没有对其的编译时支持,因此这样做没有任何好处。如果通过反射使用该对象,那么保存该实例的变量的实际类型并不重要 - 也可能是Object

这并不意味着不可能,只是演员阵容有点麻烦。该语言确实允许我们使用类型参数化类型编写仅在运行时了解给定类型的代码!

我的示例中的代码设置了一个非常简单的方法来获取 aAdapterDelegate的 an LibraryDelegate<TRunTimeType>,使用专门在运行时找到的信息。TRunTimeType您会注意到该方法中的实际转换AdapterDelegateHelper.Adapter<TRuntimeType>.adapter。查看Main代码,看看使用起来有多么容易:

using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Reflection;

namespace ConsoleApplication2
{
    // Start by declaring a delegate that looks exactly like the library method you want to call, but with TRuntimeType in place of the actual type
    public delegate void LibraryDelegate<TRuntimeType>(TRuntimeType param, Int32 num, String aStr);
    // Declare an "adapter" delegate that uses "Object" in place of TRuntimeType for every relevant parameter
    public delegate void AdapterDelegate(Object param, Int32 num, String aStr);

    public static class AdapterDelegateHelper
    {
        private class Adapter<TRuntimeType>
        {
            private readonly LibraryDelegate<TRuntimeType> libDelegate;

            public Adapter(Object LibraryInstance, String MethodName)
            {
                Type libraryType = LibraryInstance.GetType();
                Type[] methodParameters = typeof(LibraryDelegate<TRuntimeType>).GetMethod("Invoke").GetParameters().Select(p => p.ParameterType).ToArray();
                MethodInfo libMethod = libraryType.GetMethod(MethodName, methodParameters);
                libDelegate = (LibraryDelegate<TRuntimeType>) Delegate.CreateDelegate(typeof(LibraryDelegate<TRuntimeType>), LibraryInstance, libMethod);
            }

            // Method that pricecly matches the adapter delegate
            public void adapter(Object param, Int32 num, String aStr)
            {
                // Convert all TRuntimeType parameters.
                // This is a true conversion!
                TRuntimeType r_param = (TRuntimeType)param;

                // Call the library delegate.
                libDelegate(r_param, num, aStr);
            }
        }

        public static AdapterDelegate MakeAdapter(Object LibraryInstance, String MethodName, Type runtimeType)
        {
            Type genericType = typeof(Adapter<>);
            Type concreteType = genericType.MakeGenericType(new Type[] { runtimeType });
            Object obj = Activator.CreateInstance(concreteType, LibraryInstance, MethodName);
            return (AdapterDelegate)Delegate.CreateDelegate(typeof(AdapterDelegate), obj, concreteType.GetMethod("adapter"));
        }
    }

    // This class emulates a runtime-identified type; I'll only use it through reflection
    class LibraryClassThatIOnlyKnowAboutAtRuntime
    {
        // Define a number of oberloaded methods to prove proper overload selection
        public void DoSomething(String param, Int32 num, String aStr)
        {
            Console.WriteLine("This is the DoSomething overload that takes String as a parameter");
            Console.WriteLine("param={0}, num={1}, aStr={2}", param, num, aStr);
        }

        public void DoSomething(Int32 param, Int32 num, String aStr)
        {
            Console.WriteLine("This is the DoSomething overload that takes Integer as a parameter");
            Console.WriteLine("param={0}, num={1}, aStr={2}", param, num, aStr);
        }

        // This would be the bad delegate to avoid!
        public void DoSomething(Object param, Int32 num, String aStr)
        {
            throw new Exception("Do not call this method!");
        }
    }

    class Program
    {

        static void Main(string[] args)
        {
            Type castToType = typeof(string);
            Type libraryTypeToCall = typeof(LibraryClassThatIOnlyKnowAboutAtRuntime);

            Object obj = Activator.CreateInstance(libraryTypeToCall);

            AdapterDelegate ad1 = AdapterDelegateHelper.MakeAdapter(obj, "DoSomething", castToType);
            ad1("param", 7, "aStr");

            Console.ReadKey();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我正在查看旧帖子。我并没有最终找到一种方法来做我想做的事,并重新编写了很多代码。关于编译器和这个例子的评论对我来说很有意义。虽然我没有使用该示例,但我很欣赏 Cosmin 的努力 (2认同)