C#中的Activator.CreateInstance和Generic方法

时间:2012-04-13 08:16:02

标签: c#-4.0

interface IExecutor
{
   void Execute();
}

class Executor2<T> where T : IExecutor
{
    public void Execute()
    {
        var ex = (T)Activator.CreateInstance(typeof(T));
        ex.Execute();
    }
}

这是一个采访中的问题。他们告诉我,有时这个代码会掉落(引起异常),并且至少有3个原因可能导致问题。不知道有什么例外。但方法Execute创建良好,实现没有错误。

有人对此提出建议吗?

编辑:至少有3个原因可能会导致问题。这些原因是什么?

3 个答案:

答案 0 :(得分:4)

从表面上看,我可以看到一些问题。

  1. 代码无法编译,但我可以忽略它并使其编译。
  2. 代码没有按照您的想法执行。
  3. 要解释2:您在类定义中使用T上的约束指定类型IExecutor,但是您在方法级别定义了另一个类型T而没有约束。这不会编译。

    如果我修复此问题并从方法中删除<T>定义,我可以看到它失败的一些原因而没有太多警告:

    1. ex为空。
    2. 类型T没有定义公共无参数构造函数。
    3. 可能无法加载包含T
    4. 的DLL

      雅库布发现:

      1. T可以是一个接口(没有构造函数)。
      2. T可以是抽象类,这些不允许直接创建实例。
      3. 第一个可以防止使用空检查if (ex != null),第二个可以防止使用另一个通用约束new()

        class Executor2<T> where T : IExecutor, new()
        {
        }
        

        显然,您还可以修改代码以包含异常日志记录。这可能有助于弄清楚实际问题的内容,而不仅仅是在黑暗中刺伤:

        public void Execute<T>()
        {
            try
            {
                var ex = (T)Activator.CreateInstance(typeof(T));
                ex.Execute();
            }
            catch (Exception ex)
            {
                Log(ex); // Mystical logging framework.
                throw;
            }
        }
        

        考虑到我不理解这个问题,这是我可以拼凑的唯一答案。

        如果我在接受采访时被问到这个问题,我可能会说我无法命名所有3,但我知道如何更改代码以使其更易于维护并告诉我出了什么问题。然后我可能会走路去寻找毫无意义的面试问题。

答案 1 :(得分:2)

T可能是界面抽象类 - 您无法创建它们的实例,或T没有无参数构造

此外,var ex = (T)Activator.CreateInstance(typeof(T));可以重写为var ex = Activator.CreateInstance<T>();

答案 2 :(得分:2)

是否假设T的设计没有错误?我的意思是,如果T定义了一个执行Bad Stuff的静态构造函数,那么T的类型初始化将失败,如果它没有无参数构造函数,则会出现不同的异常。

就此而言,如果T定义了一个无参数的构造函数,它将失败,那么它也会被破坏。

此外,如果类型具有私有构造函数,您将收到错误。或者,如果类型继承自将导致TypeInitialisationException的类型

[编辑]

试试这个:

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            try { 
                new Executor2<IExecutor>().Execute();
            }
            catch { Console.WriteLine("Failed IExecutor"); }

            try { new Executor2<AbstractExecutorWithImpl>().Execute(); }
            catch { Console.WriteLine("Failed AbstractExecutorWithImpl"); }

            try { new Executor2<AbstractExecutorWithNoImpl>().Execute(); }
            catch { Console.WriteLine("Failed AbstractExecutorWithNoImpl"); }

            try { new Executor2<ConcreteExecutor>().Execute(); }
            catch { Console.WriteLine("Failed ConcreteExecutor"); }

            try { new Executor2<DerivedExecutor>().Execute(); }
            catch { Console.WriteLine("Failed DerivedExecutor"); }

            try { new Executor2<DerivedExecutorWithBadConstr>().Execute(); }
            catch { Console.WriteLine("Failed DerivedExecutorWithBadConstr"); }

            try { new Executor2<DerivedExecutorWithPrivateConstr>().Execute(); }
            catch { Console.WriteLine("Failed DerivedExecutorWithPrivateConstr"); }

            try { new Executor2<DerivedExecutorWithPublicBadConstr>().Execute(); }
            catch { Console.WriteLine("Failed DerivedExecutorWithPublicBadConstr"); }

            Console.ReadLine();
        }
    }


    interface IExecutor
    {
        void Execute();
    }

    abstract class AbstractExecutorWithImpl : IExecutor
    {
        public void Execute()
        {
            Console.Write("Executing AbstractExecutorWithImpl ");
        }
    }
    abstract class AbstractExecutorWithNoImpl : IExecutor
    {
        public abstract void Execute();
    }

    class ConcreteExecutor : IExecutor
    {
        public void Execute()
        {
            Console.WriteLine("Executing ConcreteExecutor");
        }
    }

    class DerivedExecutor : AbstractExecutorWithNoImpl
    {
        public override void Execute()
        {
            Console.WriteLine("Executing DerivedExecutor");
        }
    }

    class DerivedExecutorWithBadConstr : IExecutor
    {
        static DerivedExecutorWithBadConstr() { throw new Exception("Static initialisation Exception"); }
        public void Execute()
        {
            Console.WriteLine("Executing DerivedExecutorWithBadConstr");
        }
    }

    class DerivedExecutorWithPrivateConstr : DerivedExecutor
    {
        private DerivedExecutorWithPrivateConstr() { }
    }
    class DerivedExecutorWithPublicBadConstr : DerivedExecutorWithBadConstr
    {
        public DerivedExecutorWithPublicBadConstr() : base() { }
    }

    class Executor2<T> where T : IExecutor
    {
        public void Execute()
        {
            var ex = (T)Activator.CreateInstance(typeof(T));
            ex.Execute();
        }
    }
}