Принцип подстановки лисков и обработка исключений

В нем говорится, что класс Derived не должен генерировать какое-либо исключение, которое не известно базовому классу, я пытаюсь выяснить, как он работает, в базовом классе я бросаю System.Exception, а в Derived я бросаю ArgNullException (). Может кто-нибудь объяснить, это нормально

 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");
                }
            }           

        }

person New Coder    schedule 21.08.2013    source источник
comment
Исключение, создаваемое базовым классом, должно быть Подтипом исключений, созданных суперклассом. Ваш пример даже не выдает никаких исключений (из-за блока catch).   -  person aknon    schedule 12.12.2013


Ответы (3)


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. Теперь любой, кто знает только о базовом классе, будет иметь блоки catch только для ArgumentNullException, поскольку это то, что они ожидают. Поэтому их приложение завершится ошибкой, когда подкласс выбрасывает 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
        }
    }
}
person jgauffin    schedule 21.08.2013
comment
Дополнительное примечание: в отличие от C #, Java имеет проверенные исключения для устранения этого нарушения LSV во время компиляции. - person Matthias Meid; 21.08.2013

В опубликованном вами коде нет проблемы с точки зрения подтипов, потому что в обоих случаях вы перехватываете исключение в той же области, в которой оно возникло. Но предположим, что у производного foo не было предложения catch, а у базового класса был следующий код:

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

Базовый класс исходит из предположения, что foo выдает только ArgumentOutOfRange, что нарушит производный класс, выбрасывая ArgumentNull.

person nmclean    schedule 21.08.2013

Лучшее понимание принципа подстановки Лискова можно найти здесь
https://stackoverflow.com/search?q=liskov+substitution+principle

person aknon    schedule 12.12.2013