为实现抽象的 类 创建一个 DTO 是一种不好的做法吗?

Is it a bad practice to create one DTO for many classes that implements an abstract one?

例如:

我有:

我可以按如下方式使用 DTO 吗?

AnimalDto {
    public string Name { get; set;} 
    public string Country { get; set;}
    public string Size { get; set;}
    public AnimalType Type { get; set}
}

这个怎么样:

public abstract AnimalDTO
{
    public static AnimalDTO Create(Animal animal)
    {
        var dog = animal as Dog;
        var cat = animal as Cat;
        if (dog != null)
        {
             return Dog(dog.Country);
        }
        else
        {
            return Cat(cat.Size);
        }
    }

    public static AnimalDTO Dog(string country) => 
        new Animals.Dog(country);

    public static AnimalDTO Cat(string size) =>
        new Animals.Cat(size);

    public abstract void Switch(Action<string> isDog, Action<string> isCat);

    private static class Animals
    {
        public class Dog : AnimalDTO
        {
            readonly string country;
            public Dog(string country)
            {
                this.country = country;
            }
            public override void Switch(Action<string> isDog, Action<string> isCat) => isDog(country);
    }
    public class Cat : AnimalDTO
        {
            readonly string size;
            public Dog(string size)
            {
                this.size = size;
            }
            public override void Switch(Action<string> isDog, Action<string> isCat) => isCat(size);
    }
}

例如:

public void CallFactory(Animal animal)
{
     var a = AnimalDTO.Create(animal);
    Factory(a);
}

public void Factory(AnimalDTO animal)
{
    animal.Switch(
        isDog: (country) => {
            // here you can be sure that the animal is dog
            // you can use country variable
            Console.Writeline($"It is a dog! from country {country}");
        },
        isCat: (size) => {
           // it is a cat
           Console.Writeline($"it is a cat of size {size}");
        });
}

我觉得这是一个 XY 问题。为什么要使用摘要 class?

总是一种避免创建摘要的方法class - 除了必须从您所在的图书馆中提取class摘要消耗但无法控制。如何?使用接口,当您需要通用功能时,使用静态函数或与另一个组合使用 class.

我知道这不是您问题的直接答案,但它可能会解决您的问题。

public interface IAnimal
{
    string Name { get; set; }
}

public class Dog : IAnimal
{
    public string Name { get; set; }
    public string Country { get; set; }
}

public class Cat : IAnimal
{
    public string Name { get; set; }
    public string Size { get; set; }
}

由此,您最终得到两个 classes,它们都可以用作 DTO,它们都没有不必要的属性。

在运行时你可以输入检查。

IAnimal myAnimal = ... ;

Helpers.DoSomethingWithAnimal(myAnimal);

switch (myAnimal)
{
    case (Cat cat):
        Helpers.DoSomethingWithCat(cat);
        break;

    case (Dog dog):
        Helpers.DoSomethingWithDog(dog);
        break;
}

序列化时,您可以插入一个额外的 属性 来跟踪您需要将数据反序列化回的动物类型。

{
    name: "My Dog",
    country: "Romania",
    "__animal-type": "dog"
}

要回答这个问题,您可以查看 SOLID 原则,尤其是 the Single Responsibility Principle,它指出 class 必须只有 一个 改变的原因。

如果您的 DTO 重新组合属于动物王国的所有 classes 的所有属性,则每次需要更改这些 classes 时,它都必须更改。如果 Cat 更改,它将更改。如果狗改变,它也会改变。等等。我会避免这种情况。

如其他答案所述,如果可能的话,可能值得重新考虑设计。