如何避免强制转换派生类型-违反Liskov原则

Mar*_*ans 0 c# liskov-substitution-principle solid-principles

我想避免使用将基类类型转换为派生类类型的方法,我可以成功完成此操作。

我已经编写了代码来演示我已经尝试过的内容。

public abstract class Animal : IAnimal
{
    public void Move()
    {        
    }
}

public interface IAnimal
{
     void Move();
}

public interface IDog:IAnimal
{
    void bark();
}

public class Dog : IDog
{
    public void Move()
    {

    }

    public void bark()
    {

    }
}

static void Main(string[] args)
{
    Animal animal = null;
    IDog dog = animal as IDog;

    dog.bark(); // can access specialized method

    IAnimal puppy = new Dog();
    puppy.Move(); // can only access generic functions    
}
Run Code Online (Sandbox Code Playgroud)

如何重新设计类以访问“树皮”方法而无需强制转换?

Kac*_*ski 5

简短答案:您不能,也应该不能。

相反,您可以做的是MakeNoise()IAnimal接口中实现一个方法,因为您通常希望动物发出声音。

但是,如果您坚持要Bark()继续使用IDog,就不会期望IDuck它能够访问它-它应该有一个Quack()方法。向下转换到的对象都不可用,IAnimal因为您如何猜测它是a Duck还是a Dog


我将发布更多关于“为什么在编程中可能需要继承”的“现实生活”示例,因为您提供的示例有点像“书本示例”,因此它也是晦涩而模糊的。

using System.Collections.Generic;

namespace ConsoleApp1
{
    public static class DocumentHandling
    {
        public static List<IAccountable> Documents;
        public static dynamic InternalService { get; set; }
        public static dynamic IRS { get; set; }

        public static void HandleDocuments()
        {
            foreach (var document in Documents)
            {
                document.Account();
            }
        }
    }

    public interface IAccountable
    {
        void Account();
    }

    public abstract class Document
    {
        public int DatabaseId { get; set; }
        public string Title { get; set; }

    }

    public abstract class DocumentWithPositions : Document
    {
        public int[] PositionsIds { get; set; }
    }

    public class Invoice : DocumentWithPositions, IAccountable
    {
        public void Account()
        {
            var positions = DocumentHandling.InternalService.PreparePositions(this.PositionsIds);
            DocumentHandling.IRS.RegisterInvoice(positions);
        }
    }

    public class Receipt : DocumentWithPositions, IAccountable
    {
        public void Account()
        {
            Invoice invoice = DocumentHandling.InternalService.ConvertToReceipt(this);
            invoice.Account();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

看看我如何将文档InvoiceReceipt文档都塞进一个列表中(因为它们被向下转换为IAccountable)?现在,即使它们的具体实现对会计过程的处理方式不同,我也可以一次对其全部进行会计处理。

  • 可以肯定,worm不会发出声音。 (3认同)