【问题标题】:Activator.CreateInstance - Not able to use the return typeActivator.CreateInstance - 无法使用返回类型
【发布时间】:2012-11-25 17:31:34
【问题描述】:

我正在尝试手动滚动我自己的 IoC 工具。

这是 IoC 代码的一部分:

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

我想返回一个泛型类型 T 的对象。我做不到。

我也无法对其进行类型转换。我只使用一个具有两个依赖项的接口。 (IPredictingFuture, EartAndSkyPrediction, BadConnections)

我正在尝试将其类型转换为接口类型。 (为了访问我的客户端代码中的方法。)但这也行不通。

我错过了什么?

【问题讨论】:

  • “我也无法进行类型转换。” - 为什么不?真的不清楚你要做什么,或者为什么你期望能够使用你只在执行时才知道的类型的成员......
  • @JonSkeet,让我添加更多代码来清除它。

标签: c# object ioc-container


【解决方案1】:

在您的方法中,contract 仅在运行时已知,因此无法在编译时使用。根据您的调用者,您可以将其更改为泛型类型参数,在这种情况下您可以这样做:

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

重载,因为正如您提到的,Resolve(Type) 递归调用自己,而通用版本不能这样调用自己。

【讨论】:

  • 我认为这行不通。实际代码使用递归。它再次调用resolve。 paramList.Add(Resolve(param.ParameterType)); 。我现在正在尝试重载 Resolve...
  • @TheSilverBullet 啊,我错过了。是的,重载会解决这个问题,我会编辑。
  • @TheSilverBullet 已编辑,这样你可以调用Resolve&lt;IPredictingFuture&gt;(),在编译时已知它会返回IPredictingFuture,或者你可以调用Resolve(typeof(IPredictingFuture)),它返回一个object你必须在呼叫者的身边投射。
  • @TheSilverBullet 我没有注意到你已经把这个放在你自己的答案中了:)
【解决方案2】:

调整这个场地的命名空间,我已经用了很多年了……

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

不确定这是否会帮助您,但我将其用作业务规则评估引擎的一部分...

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

}

【讨论】:

    【解决方案3】:

    谢谢大家的回复。 我添加了这个重写的 Resolve 方法

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

    现在,我得到了正确的类型。这是客户端代码:

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

    这样,预测后的智能感知就可以正常工作了。

    如果有读者因为试图制作 IoC 容器而遇到这个问题,我会向他们指出这些很棒的链接:

    1. 33 liner IoC by Ken
    2. 15 liner IoC by Ayende
    3. 跟进post by Ayende,了解为什么不应该编写自己的 IoC 代码
    4. Good link 关于 IoC 容器
    5. Another SO question 谈论 IoC

    【讨论】:

      猜你喜欢
      • 2014-07-24
      • 2023-04-03
      • 2015-10-14
      • 2019-06-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多