2
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 个可能导致问题的原因。这些原因是什么?

4

3 回答 3

4

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

  1. 该代码无法编译,但我可以忽略它并使其编译。
  2. 代码没有做你认为的事情。

解释 2:您T在类定义中指定了一个带有约束的类型IExecutor,但是您随后T在没有约束的方法级别定义了另一个类型。这不编译。

如果我解决这个问题并<T>从方法中删除定义,我可以看到它失败的许多原因而没有太多警告:

  1. ex一片空白。
  2. 类型T没有定义公共无参数构造函数。
  3. 也许它无法加载包含T.

正如 Jakub 所发现的:

  1. T可能是一个接口(没有构造函数)。
  2. T可能是一个抽象类,这些不允许直接创建实例。

第一个可以防止使用空检查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 个,但我知道如何更改代码以使其更易于维护并告诉我出了什么问题。然后我很可能会因为问一些毫无意义的面试问题而走路。

于 2012-04-13T08:25:27.560 回答
2

T可能是接口抽象类- 您不能创建它们的实例,或者T没有无参数构造函数。

var ex = (T)Activator.CreateInstance(typeof(T));可以改写为var ex = Activator.CreateInstance<T>();

于 2012-04-13T08:48:30.090 回答
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();
        }
    }
}
于 2012-04-13T08:52:25.880 回答