【问题标题】:Dynamic object cast to type known at runtime only动态对象转换为仅在运行时已知的类型
【发布时间】:2013-10-06 03:36:25
【问题描述】:

情况: 类型 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?

【问题讨论】:

  • 这有什么意义?你能提供你实际想要达到的目标的背景吗?
  • 由于您在编译时不知道类型,我假设您将使用反射/动态与对象进行交互,在这种情况下没有意义或不需要强制转换它,该对象的类型是无论如何。强制转换仅对您知道与对象进行类型安全交互的类型有用。
  • Cast 是一种扩展方法,可用于实现IEnumerable 的类,如List&lt;T&gt;,但不适用于简单的具体类。
  • 您能否编辑并向我们展示您尝试调用的方法,以及您要调用的参数?
  • 我们需要您尝试调用的方法的完整原型,以及您尝试调用它的参数类型。但是,我也同意斯潘德的观点。您应该发布一个新问题“为什么这个动态方法调用不起作用?”而是。

标签: c#


【解决方案1】:

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

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

我的示例中的代码设置了一个非常简单的方法来获取AdapterDelegateLibraryDelegate&lt;TRunTimeType&gt;,使用仅在运行时找到的信息。您会注意到在AdapterDelegateHelper.Adapter&lt;TRuntimeType&gt;.adapter 方法中实际转换为TRunTimeType。查看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();
        }
    }
}

【讨论】:

  • 我正在浏览旧帖子。我并没有最终找到一种方法来做我想做的事,而是重新编写了很多代码。关于编译器和这个例子的评论对我来说很有意义。虽然我没有使用示例,但我感谢 Cosmin 的努力
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多