2011-06-22 57 views
0

我從C#4.0複製了這段代碼,其中使用了Attribute/Reflection API來控制動作:要運行的測試的數量並顯示錯誤消息。使用.NET反射和屬性來控制動作

當我運行代碼時,我得到了這個結果。

Method Method1 will be tested; reps=1; msg=; memo= 
Test1 
Method Method2 will be tested; reps=3; msg=; memo=abc 
Test2 
Test2 
Test2 
Method Method3 will be tested; reps=3; msg=Debugging Time!; memo= 
Test3 
Test3 
Test3 

Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object 
    at Hello.Main() [0x00000] in <filename unknown>:0 

爲什麼這是Unhandled Exception

的源代碼如下:

using System; 
using System.Reflection; 

[AttributeUsage (AttributeTargets.Method)] 
public sealed class TestAttribute : Attribute 
{ 
    public int Repititions; 
    public string FailureMessage; 
    public string Memo; 

    public TestAttribute() : this(1) {} 
    public TestAttribute(int repititions) {Repititions = repititions;} 
} 

class Foo 
{ 
    [Test] 
    public void Method1() 
    { 
     Console.WriteLine("Test1"); 
    } 
    [Test(3, Memo="abc")] 
    public void Method2() 
    { 
     Console.WriteLine("Test2"); 
    } 
    [Test(3, FailureMessage="Debugging Time!")] 
    public void Method3() 
    { 
     Console.WriteLine("Test3"); 
    } 
} 

class Hello 
{ 
    static void Main() 
    { 
     foreach (MethodInfo mi in typeof(Foo).GetMethods()) 
     { 
      TestAttribute att = (TestAttribute) Attribute.GetCustomAttribute(mi, typeof(TestAttribute)); 
      if (att != null) 
       Console.WriteLine("Method {0} will be tested; reps={1}; msg={2}; memo={3}", mi.Name, att.Repititions, att.FailureMessage, att.Memo); 
       for (int i = 0; i < att.Repititions; i++) 
        try 
        { 
         mi.Invoke(new Foo(), null); 
        } 
        catch (Exception ex) 
        { 
         throw new Exception ("Error: " + att.FailureMessage, ex); 
        } 
     } 
    } 
} 
+0

看起來你在Console.WriteLine(第一個)和for語句周圍缺少範圍。 –

回答

3

您錯過了if (att != null)foreach中的一些花括號{}。縮進本身是不夠的。

class Hello 
{ 
    static void Main() 
    { 
     foreach (MethodInfo mi in typeof(Foo).GetMethods()) 
     { 
      TestAttribute att = (TestAttribute) Attribute.GetCustomAttribute(mi, typeof(TestAttribute)); 
      if (att != null) 
      { 
       Console.WriteLine("Method {0} will be tested; reps={1}; msg={2}; memo={3}", mi.Name, att.Repititions, att.FailureMessage, att.Memo); 
       for (int i = 0; i < att.Repititions; i++) 
       { 
        try 
        { 
         mi.Invoke(new Foo(), null); 
        } 
        catch (Exception ex) 
        { 
         throw new Exception ("Error: " + att.FailureMessage, ex); 
        } 
       } 
      } 
     } 
    } 
} 
+0

公平起見,for語句不需要它,因爲編譯器認爲try-catch是一個語句。 =) –

+0

是的...但誰想看看這個代碼? –

+0

可讀性是一回事。 =) –

0

你很可能打不具有屬性的內部方法,因此該行失敗:

TestAttribute att = (TestAttribute) Attribute.GetCustomAttribute(mi, typeof(TestAttribute)); 

要使用安全-cast:

TestAttribute att = Attribute.GetCustomAttribute(mi, typeof(TestAttribute)) as TestAttribute; 
+0

您可以明確地將null轉換爲引用對象。在調用null上的屬性時發生錯誤。這不是你的改變所固定的。 –

+0

如果該行出現錯誤,則會導致InvalidCastException,而不是NullReferenceException。 =) –

1

因爲MethodInfo miToString inheri從沒有TestAttribute的物體中提取。所以現在你的價值是att是空的,你試着打電話給att.Repititions就可以了。您可以將其更改爲

if (att != null) 
{ 
    Console.WriteLine("Method {0} will be tested; reps={1}; msg={2}; memo={3}", mi.Name, att.Repititions, 
         att.FailureMessage, att.Memo); 
    for (int i = 0; i < att.Repititions; i++) 
     try 
     { 
      mi.Invoke(new Foo(), null); 
     } 
     catch (Exception ex) 
     { 
      throw new Exception("Error: " + att.FailureMessage, ex); 
     } 
} 

要修復它。

0

我在您的代碼中添加了一個存根行 - 您試圖從System.String的ToString()方法獲取自定義屬性。

foreach (MethodInfo mi in typeof(Foo).GetMethods()) 
    { 
     Console.WriteLine(mi.ToString()); 
     TestAttribute att = (TestAttribute) Attribute.GetCustomAttribute(mi, typeof(TestAttribute)); 
     if (att != null) 
      Console.WriteLine("Method {0} will be tested; reps={1}; msg={2}; memo={3}", mi.Name, att.Repititions, att.FailureMessage, att.Memo); 
      for (int i = 0; i < att.Repititions; i++) 
       try 
       { 
        mi.Invoke(new Foo(), null); 
       } 
       catch (Exception ex) 
       { 
        throw new Exception ("Error: " + att.FailureMessage, ex); 
       } 
    }