C# liskov替换原理与异常处理

C# liskov替换原理与异常处理,c#,oop,solid-principles,design-principles,C#,Oop,Solid Principles,Design Principles,它说派生类不应该抛出基类不知道的任何异常,我正在试图找到它是如何工作的,在基类中我抛出System.exception,在派生类中我抛出ArgNullException()。 有人能解释一下吗 class b { virtual public void foo() { try { if (true)

它说派生类不应该抛出基类不知道的任何异常,我正在试图找到它是如何工作的,在基类中我抛出System.exception,在派生类中我抛出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");
                }
            }           

        }
在这种情况下,您将在基类中抛出尽可能少的特定异常(另一个讨论是为什么这样做很糟糕)。在这种情况下,使用子类的任何人都将能够捕获到该异常,无论您抛出的异常有多具体


让我们假设情况正好相反。基类抛出
ArgumentNullException
,子类抛出
Exception
。现在,任何只知道基类的人都只能获得
ArgumentNullException
的catch块,因为这是他们所期望的。因此,当子类抛出异常时,它们的应用程序将失败

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将违反该假设。

可以在这里找到对Liskov替代原理的更好理解

附加说明:与C#不同,Java在编译时检查了异常以解决此LSV冲突。基类引发的异常应该是超类引发的异常的子类型。您的示例甚至不会引发任何异常(因为catch块)。
try {
    this.foo();
} catch (ArgumentOutOfRangeException e) {
    ...
}