2012-04-13 370 views
2
interface IExecutor 
{ 
    void Execute(); 
} 

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

這是一個面試時的問題。他們告訴我,有時候這段代碼會下降(導致異常),至少有三個原因可能會導致問題。不知道有什麼例外。但方法Execute創建好,它的實現沒有錯。C#中的Activator.CreateInstance和泛型方法#

有沒有人有關於此的建議?

編輯:至少有3個原因可能導致問題。這些原因是什麼?

+0

是什麼3個故障可能發生的問題? – 2012-04-13 08:20:16

+0

至少有3個可能導致問題的原因。這些原因是什麼? – Alexandre 2012-04-13 08:43:25

回答

4

表面上我可以看到一些問題。

  1. 代碼不能編譯,但我可以忽略它並編譯它。
  2. 該代碼不會做你認爲它的作用。

要說明2:您指定的類定義與IExecutor約束的類型T,但你定義在方法級別其他類型T沒有約束。這不會編譯。

如果我解決這個問題,並刪除該方法的定義<T>我可以看到一些原因吧沒有太多的警告失敗:

  1. ex爲空。
  2. 類型T沒有定義公共無參數構造函數。
  3. 也許它無法加載包含T的DLL。

如發現通過的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,但我知道如何將代碼更改爲更易維護,並告訴我什麼是錯誤的。然後,我可能會走開詢問毫無意義的面試問題。

+1

'類型T沒有定義公共無參數的構造函數。還有什麼? – Alexandre 2012-04-13 08:40:43

+0

@AlexMaslakov我對這個問題很困惑。你已經知道答案,只是提問人們? – 2012-04-13 08:41:48

+1

我只知道無參構造函數的答案。 – Alexandre 2012-04-13 08:50:16

2

T可能是接口抽象類 - 你不能創建它們的實例,或T沒有參數的構造函數。

此外,var ex = (T)Activator.CreateInstance(typeof(T));可以改寫爲var ex = Activator.CreateInstance<T>();

+0

+1沒有考慮接口或抽象類的一部分,但是當我想到它時,前者在你假設一個公共無參數構造函數時被覆蓋。 – 2012-04-13 08:53:12

2

是它假定存在T的設計沒有錯嗎?我的意思是,如果T定義了一個不好的東西的靜態構造函數,那麼爲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(); 
     } 
    } 
}