6

情况: 类型 baseType 仅在运行时已知。objectInstance 是 baseType 类型的子对象 objectInstance 是从对动态方法的调用中检索到的

必需的:

Type baseType = ...; // obtained at runtime
var baseDynamicInstance = (basetype) objectInstance; // or reflection cast

硬编码时,它可以工作

   var oi = (PartnerBase) objectInstance;   // this works

试过:

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;
   }

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

我看过很多例子,这表明 Type.GetMethod("Cast") 是正确的。但它不起作用。所以很明显我做错了什么。

有小费吗

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

[Microsoft.CSharp.RuntimeBinder.RuntimeBinderException] = {"'P42.RepositoryBase.GetEntityState(P42.Core.PartnerBase)' 的最佳重载方法匹配有一些无效参数"}

EDIT2: 从动态方法调用中检索到一个 ObjectInstance。该对象应用于调用动态方法。如果我硬编码下来,它就可以工作。var x = (baseobject) ObjInstance 并使用 x 调用动态方法。有用。

基类型也只在运行时才知道。有没有办法将 SpecificObject 动态转换为 BASEObject?

4

1 回答 1

5

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

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

我的示例中的代码设置了一个非常简单的方法来获取AdapterDelegatefor a 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();
        }
    }
}
于 2013-10-05T19:36:25.867 回答