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


Он говорит, что производный класс не должен выбрасывать какое-либо исключение, которое не известно базовому классу, я пытаюсь найти, как его работа, в базовом классе я выбрасываю систему.Исключение и в производном я бросаю 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");
                }
            }           

        }
3 2

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
        }
    }
}

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

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

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

Более полное понимание принципа замещения Лискова можно найти здесь
https://stackoverflow.com/search?q=liskov + замещение + Принцип