2013-10-05 13 views
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; 
    } 

ОШИБКА: null объект ref погрешность.
В ближайшем окне я вижу объектInstance.GetType(). GetMethod («Cast») возвращает null
objectInstance.GetType.GetMethods() // показывает список в непосредственном окне. // не показан метод отливки

Я рассмотрел множество примеров Это подсказывает мне, что Type.GetMethod («Cast») был прав. Но это не работает. Поэтому я явно делаю что-то неправильно.

Любые советы

EDIT: Ошибка вызова без пуха приведение к базовой зашиты

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

EDIT2: ObjectInstance извлекается из динамического вызова метода. Объект должен использоваться при вызове динамического метода. Если мне сложно записать код, он работает. var x = (baseobject) ObjInstance И вызовите динамический метод с помощью x. оно работает.

Базовый тип также известен только во время выполнения. Есть ли способ динамически выделять SpecificObject для BAseObject?

+0

О каком методе Cast вы говорите? Есть ли у вашего объекта такой метод? – usr

+1

В чем смысл этого? Можете ли вы предоставить информацию о том, чего вы на самом деле пытаетесь достичь? – spender

+3

Поскольку вы не знаете тип во время компиляции, я предполагаю, что вы собираетесь взаимодействовать с объектом с помощью функции reflection/dynamic, и в этом случае не было бы смысла или необходимости бросать его, объект имеет тип, который он есть независимо. Кастинг полезен только для типов, которые вы знаете, чтобы получить безопасное взаимодействие типа с объектом. – Chris

ответ

4

Кастинг для типа, который известен только в режиме Runtime, кажется бессмысленной операцией для компилятора: поскольку по определению он не знает тип до Runtime, для него нет поддержки времени компиляции, поэтому нет никакой пользы в этом так. Если объект используется через Reflection, то фактический Тип переменной, которая содержит экземпляр, не имеет большого значения - может также быть Object.

Это не значит, что это невозможно, это просто немного громоздко сделать. Язык позволяет нам писать код, который только что узнал о заданном типе в Runtime, используя типы с параметризацией!

Код в моем примере устанавливает очень простой способ получения AdapterDelegate для 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(); 
     } 
    } 
} 
+2

Я иду по старым сообщениям. Я не закончил поиск способа сделать то, что хотел, и переработал много кода. Комментарий к компилятору и этому примеру имеет смысл для меня. Хотя я не использовал образец, я ценю усилие Cosmin –

-2

Вы можете попробовать dynamic, если работаете на .Net4.0.

+0

любая конкретная причина, если динамика не подходит для этого случая. –

+3

'dynamic' имеет все, что с ним связано. Ваш ответ просто не затрагивает актуальную проблему. – shambulator

Смежные вопросы