简体   繁体   English

返回具有子属性 C#、.NET 的父 class

[英]Return parent class with child properties C#, .NET

I have two classes which has multiple common properties but they have their own properties as well.我有两个具有多个共同属性的类,但它们也有自己的属性。 I created a base class and then two child classes but now in my APIs, I want one return type because we have one API for both children.我创建了一个基本 class 和两个子类,但现在在我的 API 中,我想要一个返回类型,因为我们为两个孩子都有一个 API。 What should be my response class?我应该如何回应 class?

Base Class Response基础 Class 响应


public class BaseClass
{
    public string? id { get; set; }

    public string? Name { get; set; }
    
    public string Address { get; set; }
    
    public string Type {get; set;}

    public string? PhoneNumber { get; set; } = null;
}

Child 1孩子 1

public class Child1 : BaseClass
{
    public string? RollNumber { get; set; }
    
    public string HighSchoolGrade{ get; set; }

}

Child 2孩子 2

public class Child2 : BaseClass
{
    public string? Height { get; set; }
    
    public string Weight{ get; set; }

}

Now in the API, what should be my response object现在在 API 中,我的反应应该是 object

  public async Task<BaseClass?> GetAllData(string id)
    {
        //Query
        var data = //Query
        if (data.type = ChildX){
        return //Run the mapper to convert to Child1 DTO
        
        } else {

        return  //Run the mapper to convert to Child2 DTO
        }
    }

If I do the above, it does not return the properties of the child classes and only return base class because of the response object.如果我执行上述操作,它不会返回子类的属性,并且只返回基本 class 因为响应 object。 Is there a way to have a specific response type which would include Child1 or Child2 properties as well based on the data.type有没有办法拥有一个特定的响应类型,其中包括 Child1 或 Child2 属性以及基于 data.type

We are using Document DB so there are no specific properties in the DB as it is JSON data.我们使用的是文档数据库,因此数据库中没有特定属性,因为它是 JSON 数据。 I want the classes to be separate because in future we can have a lot more properties.我希望这些类是分开的,因为将来我们可以拥有更多的属性。 Is there a way to have generic response type or just remove the response type?有没有办法拥有通用响应类型或只是删除响应类型? What are the best practices in this instance?在这种情况下,最佳实践是什么?

On the contrary, it is returning all the fields and properties.相反,它正在返回所有字段和属性。 However there is no guarantee which type is being returned at compile time, so they are not automatically available at compile time, so you have to cast it at run time.但是,无法保证在编译时返回哪种类型,因此它们在编译时不会自动可用,因此您必须在运行时强制转换它。

To explain, imagine if you wrote this:为了解释,想象一下如果你写了这个:

var result = await GetAllData();
Console.WriteLine(result.RollNumber); //This would fail if Child2 was returned
Console.WriteLine(result.Height); //This would fail if Child1 was returned

Instead you have to check the type and cast it:相反,您必须检查类型并进行转换:

var result = await GetAllData();
if (result is Child1)
{
    Console.WriteLine(((Child1)result).RollNumber);
}
if (result is Child2)
{
    Console.WriteLine(((Child2)result).Height);
}

Since this is so common, there are various c# constructs to help you along, eg you could also write由于这很常见,因此有各种 c# 结构可以帮助您,例如您也可以编写

var c1= result as Child1;
if (c1!= null) Console.WriteLine(c1.RollNumber);

or或者

switch (result)
{
    case Child1 c1:
        Console.WriteLine(c1.RollNumber);
        break;
    case Child1 c2:
        Console.WriteLine(c2.Height);
        break;
}

The latter is known as "pattern matching"后者被称为“模式匹配”

As an alternative, you could use dynamic , like this:作为替代方案,您可以使用dynamic ,如下所示:

dynamic result = await GetAllData();
Console.WriteLine(result.RollNumber); 
Console.WriteLine(result.Height); 

However this does not perform as well (as it has to use Reflection to find the property at run-time) and this will raise a nasty runtime error if you accidentally access the wrong property.然而,这并不能很好地执行(因为它必须在运行时使用反射来查找属性),如果您不小心访问了错误的属性,这将引发令人讨厌的运行时错误。 So it is discouraged.所以是气馁的。

I recommend you use the pattern matching approach since that is what it is for.我建议您使用模式匹配方法,因为这就是它的用途。

So, you can't return different types from the same class, you could do something generic but the caller would need to specify the type and, if the caller can do that, they could just call the correct, typed overload.所以,你不能从同一个 class 返回不同的类型,你可以做一些通用的事情,但调用者需要指定类型,如果调用者可以这样做,他们可以调用正确的类型化重载。

Instead, you could extend your base class a little,相反,您可以稍微扩展您的基础 class,

public abstract class BaseClass
{
    ...

    public abstract SomeTypeIndicator GetType();
}

So that the caller can ask the instance what type it is.这样调用者就可以询问实例它是什么类型。

remove base class from the task, usually it is从任务中删除基础 class,通常是

public async Task<ActionResult> GetAllData(string id)
{
}

and use something like this when you get data from the API当你从 API 获取数据时使用类似的东西

var data = JObject.Parse(response.Content);
        if (data["type"] = "ChildX")
       return data.ToObject<Child1>();
   else   return data.ToObject<Child1>();
    

First change action signiture to this:首先将动作签名更改为:

  public async Task<IActionResult> GetAllData(string id)
  {
       //Code
  }

And then you can use conditions on mapping like this:然后你可以像这样在映射上使用条件:

public async Task<IActionResult> GetAllData(string id)
{
       var query= table.Find(_ => true);
      if (data.type = ChildX)
      {
          var data1 = query.Project(TableMapping.MapChild1()).SingleOrDefualt();
          return data1;
       
      } 
      else 
      {
          var data2 = query.Project(TableMapping.MapChild2()).SingleOrDefualt();
          return data2;
      }
}

public static class TableMapping
{
   public static FindExpressionProjectionDefinition<YOUR_TABLE, Child1> MapChild1()
   {
     var config = new FindExpressionProjectionDefinition<YOUR_TABLE, Child1>(tbl => new Child1
                {
                   //populate your model like this:
                   RollNumber =  tbl.roleNumber  
                });
    return config;
   }

   public static FindExpressionProjectionDefinition<YOUR_TABLE, Child2> MapChild2()
   {
     var config = new FindExpressionProjectionDefinition<YOUR_TABLE, Child2>(tbl => new Child2
                {
                   //populate your model like this:
                   Height =  tbl.height  
                });
    return config;
   }
}

If you aren't Document Db you can use Experssion<Func<TABLE,Child1>> in method signiture.如果您不是 Document Db,则可以在方法签名中使用Experssion<Func<TABLE,Child1>>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM