简体   繁体   中英

Activator.CreateInstance - Not able to use the return type

I am trying to hand-roll my own IoC tool.

This is a part of IoC code:

public static object Resolve(Type contract)
{
   Type Implementation = typeSettings[contract];

   ConstructorInfo constructor = Implementation.GetConstructors()[0];

   ParameterInfo[] constructorParam = constructor.GetParameters();

   if (constructorParam.Length == 0)
      Activator.CreateInstance(Implementation);

   List<object> paramList = new List<object>(constructorParam.Length);

   foreach(ParameterInfo param in constructorParam)
      paramList.Add(Resolve(param.ParameterType));

   return constructor.Invoke(paramList.ToArray());
}

I want to return an object of the generic type T. I am not able to do that.

I am not able to typecast it either. I am using only one interface with two dependencies. ( IPredictingFuture , EartAndSkyPrediction , BadConnections )

I am trying to typecast it to the Interface type. (In order to access the methods in my client code.) But that is not working out either.

What am I missing?

In your method, contract is only known at runtime, so it cannot be used at compile time. Depending on your callers, you may be able to change it to a generic type parameter, in which case you can do:

public static object Resolve(Type contract)
{
   Type Implementation = typeSettings[contract];

   ConstructorInfo constructor = Implementation.GetConstructors()[0];

   ParameterInfo[] constructorParam = constructor.GetParameters();

   if (constructorParam.Length == 0)
      Activator.CreateInstance(Implementation);

   List<object> paramList = new List<object>(constructorParam.Length);

   foreach(ParameterInfo param in constructorParam)
      paramList.Add(Resolve(param.ParameterType));

   return constructor.Invoke(paramList.ToArray());
}

public static T Resolve<T>()
{
   return (T)Resolve(typeof(T));
}

Overloaded because as you mention, Resolve(Type) calls itself recursively, and the generic version cannot call itself like that.

Adjusting the namespace for this venue, I've used this for years...

using System;
using System.Collections.Generic;
using DataAccess.Core.DataInterfaces;
using DataAccess.Core.Utils;

namespace StackOverflowExample
{
    public class SimpleIoC<T>
    {
        public T getInstance()
        {
            return getInstance(null);
        }

        public T getInstance(object[] initializationParameters)
        {
            Type type = Activator.CreateInstance(typeof(T), initializationParameters).GetType();
            // Any special initialization for an object should be placed in a case statement
            // using that object's type name
            switch (type.ToString())
            {
                // Example
                //case "DataAccess.Data.ApplicantDao":
                //    // - Do pre-instanciation initialization stuff here -
                //    return (T)Activator.CreateInstance(typeof(T), initializationParameters);
                default:
                    return (T)Activator.CreateInstance(typeof(T), initializationParameters);
            }
        }
    }
}

Not sure if this one will help you, but I use this as part of a Business Rule Evaluation Engine...

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading;

namespace StackOverflowExample
{
    public static class DynamicObjectFactory
    {
        private static readonly object _lock = new object();

        public static object getInstance(string assemblyName, string className)
        {
            Monitor.Enter(_lock);
            try
            {
                System.Reflection.Assembly asm = System.Reflection.Assembly.Load(assemblyName);
                return asm.CreateInstance(className, false, System.Reflection.BindingFlags.CreateInstance, null, null, null, null);
            }
            finally
            {
                Monitor.Exit(_lock);
            }
        }

    public static object getInstance(string assemblyName, string className, object[] constructorParameters)
    {
        Monitor.Enter(_lock);
        try
        {
            System.Reflection.Assembly asm = System.Reflection.Assembly.Load(assemblyName);
            return asm.CreateInstance(className, false, System.Reflection.BindingFlags.CreateInstance, null, constructorParameters, null, null);
        }
        finally
        {
            Monitor.Exit(_lock);
        }
    }
}

}

Thanks guys, for the response. I added this overridden Resolve method

public static T Resolve<T>() { return (T)Resolve(typeof(T)); }

Now, I get the type properly. This is the client code:

IPredictingFuture predictions;
predictions = IoC.Resolve<IPredictingFuture>();

This way, the intellisense after predictions works just fine.

If any of the readers landed up at this question because they are trying to cook up an IoC container, I would point them to these great links:

  1. 33 liner IoC by Ken
  2. 15 liner IoC by Ayende
  3. Followup post by Ayende on why you should not be coding your own IoC
  4. Good link about IoC containers
  5. Another SO question which talks about IoC

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM