动态对象强制转换为仅在运行时已知的类型 [英] Dynamic object cast to type known at runtime only

查看:48
本文介绍了动态对象强制转换为仅在运行时已知的类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Situation: Type baseType known only at runtime. objectInstance is a child of type baseType objectInstance was retrieved from a call to a dynamic method

必需:

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

当进行硬编码时,它起作用

when hardcoded, it works

   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()//在即时窗口中显示列表。
//未显示强制转换方法

ERROR: null object ref error.
in immediate window i see objectInstance.GetType().GetMethod("Cast") returns null
objectInstance.GetType.GetMethods() // shows a list in immediate window. // no cast method shown

我看过很多示例
这对我来说建议使用Type.GetMethod( Cast)正确。
但是它没有用。所以很明显我做错了。

I have looked at many examples That would suggest to me the Type.GetMethod("Cast") was correct. But it doesnt work.So clearly im doing something wrong.

任何提示

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

The call error without the down cast to base hardcoded


[Microsoft.CSharp.RuntimeBinder.RuntimeBinderException] = {

重载方法匹配'P42.RepositoryBase.GetEntityState(P42.Core.PartnerBase)'
有一些无效的参数}

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

EDIT2:
从动态方法调用中检索ObjectInstance。
该对象应在对动态方法的调用中使用。
如果我硬编码向下转换,它会起作用。 var x =(基础对象)ObjInstance
并使用x调用动态方法。

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.

也只能在运行时知道基本类型。
是否可以动态地将SpecificObject强制转换为BAseObject?

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

推荐答案

将类型强制转换为仅在运行时才知道的类型对编译器来说是毫无意义的操作:由于定义上直到运行时才知道类型,因此没有编译时支持,因此这样做没有任何好处。如果通过反射使用对象,则保存实例的变量的实际类型无关紧要-最好是 Object

Casting to a type that's known only at Runtime seems to be a senseless operation for the compiler: since by definition it doesn't know the type until Runtime, there's no compile-time support for it so there's no benefit in doing so. If the object is used through Reflection, then the actual Type of the variable that holds the instance doesn't matter much - might as well be Object.

这并不意味着不可能,执行转换只是有点麻烦。该语言的确使我们能够使用类型参数化的类型编写仅在运行时才知道给定类型的代码!

That doesn't mean it's not possible, it's just a bit cumbersome to do the cast. The language does allow us to write code that's only made aware of a given type at Runtime, using type-parametrised types!

我的示例中的代码设置了一个非常简单的方法使用运行时专有的信息来获取 LibraryDelegate< TRunTimeType> AdapterDelegate 。您会在 AdapterDelegateHelper.Adapter< TRuntimeType> .adapter 方法中注意到对 TRunTimeType 的实际转换。查看 Main 代码以查看它的易用性:

The code in my example sets a very simple method to obtain an AdapterDelegate for a LibraryDelegate<TRunTimeType>, using information exclusively found at runtime. You'll notice the actual cast to TRunTimeType in the AdapterDelegateHelper.Adapter<TRuntimeType>.adapter method. Look at the Main code to see how easy this is to use:

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

这篇关于动态对象强制转换为仅在运行时已知的类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆