[英]Return parent class with child properties C#, .NET
我有两个具有多个共同属性的类,但它们也有自己的属性。 我创建了一个基本 class 和两个子类,但现在在我的 API 中,我想要一个返回类型,因为我们为两个孩子都有一个 API。 我应该如何回应 class?
基础 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;
}
孩子 1
public class Child1 : BaseClass
{
public string? RollNumber { get; set; }
public string HighSchoolGrade{ get; set; }
}
孩子 2
public class Child2 : BaseClass
{
public string? Height { get; set; }
public string Weight{ get; set; }
}
现在在 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
}
}
如果我执行上述操作,它不会返回子类的属性,并且只返回基本 class 因为响应 object。 有没有办法拥有一个特定的响应类型,其中包括 Child1 或 Child2 属性以及基于 data.type
我们使用的是文档数据库,因此数据库中没有特定属性,因为它是 JSON 数据。 我希望这些类是分开的,因为将来我们可以拥有更多的属性。 有没有办法拥有通用响应类型或只是删除响应类型? 在这种情况下,最佳实践是什么?
相反,它正在返回所有字段和属性。 但是,无法保证在编译时返回哪种类型,因此它们在编译时不会自动可用,因此您必须在运行时强制转换它。
为了解释,想象一下如果你写了这个:
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
相反,您必须检查类型并进行转换:
var result = await GetAllData();
if (result is Child1)
{
Console.WriteLine(((Child1)result).RollNumber);
}
if (result is Child2)
{
Console.WriteLine(((Child2)result).Height);
}
由于这很常见,因此有各种 c# 结构可以帮助您,例如您也可以编写
var c1= result as Child1;
if (c1!= null) Console.WriteLine(c1.RollNumber);
或者
switch (result)
{
case Child1 c1:
Console.WriteLine(c1.RollNumber);
break;
case Child1 c2:
Console.WriteLine(c2.Height);
break;
}
后者被称为“模式匹配”
作为替代方案,您可以使用dynamic
,如下所示:
dynamic result = await GetAllData();
Console.WriteLine(result.RollNumber);
Console.WriteLine(result.Height);
然而,这并不能很好地执行(因为它必须在运行时使用反射来查找属性),如果您不小心访问了错误的属性,这将引发令人讨厌的运行时错误。 所以是气馁的。
我建议您使用模式匹配方法,因为这就是它的用途。
所以,你不能从同一个 class 返回不同的类型,你可以做一些通用的事情,但调用者需要指定类型,如果调用者可以这样做,他们可以调用正确的类型化重载。
相反,您可以稍微扩展您的基础 class,
public abstract class BaseClass
{
...
public abstract SomeTypeIndicator GetType();
}
这样调用者就可以询问实例它是什么类型。
从任务中删除基础 class,通常是
public async Task<ActionResult> GetAllData(string id)
{
}
当你从 API 获取数据时使用类似的东西
var data = JObject.Parse(response.Content);
if (data["type"] = "ChildX")
return data.ToObject<Child1>();
else return data.ToObject<Child1>();
首先将动作签名更改为:
public async Task<IActionResult> GetAllData(string id)
{
//Code
}
然后你可以像这样在映射上使用条件:
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;
}
}
如果您不是 Document Db,则可以在方法签名中使用Experssion<Func<TABLE,Child1>>
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.