2013-08-21 91 views
2

它說,派生類不應該拋出任何基類未知的異常,我想找到它的工作,在基類中我拋出System.Exception和Derived我拋出ArgNullException()。 有人可以解釋爲,這是好的liskov替代原則和異常處理

class b 
     { 
      virtual public void foo() 
      { 
       try 
       { 
        if (true) 
         throw new System.Exception(); 
       } 
       catch (Exception ex) 
       { 
        Console.WriteLine("in base"); 

       } 
      } 


     } 
     class a : b 
     { 
      override public void foo() 
      { 
       try 
       { 
        if (true) 
         throw new ArgumentNullException(); 
       } 
       catch (Exception ex) 
       { 
        Console.WriteLine("in dervied"); 
       } 
      }   

     } 
+0

異常基類拋出應該是由超類拋出的異常的子類型。你的例子甚至不會拋出任何異常(使用catch塊)。 – aknon

回答

7
class MyClass 
{ 
    public virtual void Foo() 
    { 
     if (true) 
      throw new System.Exception(); 
     } 
    } 
} 

class MyDerivedClass : MyClass 
{ 
    public override void Foo() 
    { 
     if (true) 
      throw new ArgumentNullException(); 
     } 
    }   
} 


public class Program 
{ 
    public static void Main() 
    { 
     try 
     { 
      // a factory creating the correct 
      // MyClass derived instance 
      var myClass = someFactory.Create(); 

      myClass.Foo(); 
     } 
     catch (Exception) 
     { 
      // will work. 
     } 
    } 
} 

在這種情況下,你扔了至少特定的異常可能在基類(爲什麼,吸是另一個討論)。正如在這樣的情況下,無論您拋出多麼特殊的異常,使用子類的任何人都能夠捕捉到這一點。


讓我們假設它是相反的。基類拋出ArgumentNullException和子類Exception。現在,只有知道基類的人才會有ArgumentNullException的catch塊,因爲這正是他們所期望的。當子類投擲Exception時,他們的申請將失敗。

class MyClass 
{ 
    public virtual void Foo() 
    { 
     if (true) 
      throw new ArgumentNullException(); 
     } 
    } 
} 

class MyDerivedClass : MyClass 
{ 
    public override void Foo() 
    { 
     if (true) 
      throw new Exception(); 
     } 
    }   
} 


public class Program 
{ 
    public static void Main() 
    { 
     try 
     { 
      // a factory creating the correct 
      // MyClass derived instance 
      var myClass = someFactory.Create(); 

      myClass.Foo(); 
     } 
     catch (ArgumentNullException) 
     { 
      // won't work since the subclass 
      // violates LSP 
     } 
    } 
} 
+0

補充說明:與C#不同,Java在編譯時檢查異常*以解決此LSV違規問題。 –

1

在您發佈的代碼中,在子類型方面沒有問題,因爲在這兩種情況下,您都會在與它相同的範圍內捕獲異常。但是,假設派生foo沒有一個catch子句,基類有下面的代碼:

try { 
    this.foo(); 
} catch (ArgumentOutOfRangeException e) { 
    ... 
} 

的基類是要做出foo只拋出ArgumentOutOfRange,其派生類就違反假設通過拋出ArgumentNull。