C# 从基类和派生类之外的方法返回任何派生类类型

C# 从基类和派生类之外的方法返回任何派生类类型,c#,generics,inheritance,C#,Generics,Inheritance,我有三个类:BaseInfo,CarInfo,和PetInfo。BaseInfo类是基类CarInfo继承自BaseInfo,并具有与汽车相关的属性。最后,PetInfo还继承自BaseInfo,并具有与宠物相关的属性: public class BaseInfo { [JsonIgnore] public int UserId { get; set; } [JsonIgnore] public string UserName { get; set; } [JsonIgnor

我有三个类:
BaseInfo
CarInfo
,和
PetInfo
BaseInfo
类是基类
CarInfo
继承自
BaseInfo
,并具有与汽车相关的属性。最后,
PetInfo
还继承自
BaseInfo
,并具有与宠物相关的属性:

public class BaseInfo
{
  [JsonIgnore]
  public int UserId { get; set; }
  [JsonIgnore]
  public string UserName { get; set; }
  [JsonIgnore]
  public DateTime RegistrationDate { get; set; } 
  [JsonIgnore]
  public DateTime LastUpdated { get; set; }    
}

public class CarInfo : BaseInfo
{
  [JsonPropertyName("car_make")] 
  public string Make { get; set; }
  [JsonPropertyName("car_model")]
  public string Model { get; set; }  
  …
}

public class PetInfo : BaseInfo
{
  [JsonPropertyName("pet_breed")] 
  public string Breed { get; set; }
  [JsonPropertyName("pet_weight")]
  public long Weight { get; set; } 
  …
}
然后,我有一个服务,其目的是检索数据,并且在所讨论的方法中,为特定用户创建汽车或宠物列表:

public class SomeService : ISomeService
{
  public List<ANY_OF_THE_DERIVED_CLASSES> GetInfoList(string type, int userId)
  {
    List<ANY_OF_THE_DERIVED_CLASSES> infoList = new List<ANY_OF_THE_DERIVED_CLASSES>;
    switch (type)
    {
      case "car":
        infoList = GetCarList(userId);
        break;
      case "pet":
        infoList = GetPetList(userId);
        break;
      default:
        break;
    }
    return infoList;
  }

  private List<CarInfo> GetCarList(int userId)
  {
    var carList = new List<CarInfo>();

    //Logic that receives manipulates and serializes data against CarInfo and adds to list

    return carList;
  }

  private List<PetInfo> GetPetList(int userId)
  {
    var petList = new List<PetInfo>();

    //Logic that receives manipulates and serializes data against PetInfo and adds to list

    return petList;
  }
}

有没有可能让
GetInfoList
方法能够返回
List
List

注释中@Camilo Terevinto的指导完全正确,但如果您是泛型新手,可能会给您留下一些额外的问题。为了提供一个更全面的示例,下面是您提出的代码应该是什么样子的:

ISomeService
公共接口服务
{
List GetInfoList(int userId),其中T:BaseInfo;
}
SomeService
公共类SomeService:ISomeService
{
public List GetInfoList(int userId),其中T:BaseInfo
{
列表信息列表;
开关(名称(T))
{
案例名称(CarInfo):
infoList=GetCarList(userId)作为列表;
打破
案件名称(PetInfo):
infoList=GetPetList(userId)作为列表;
打破
违约:
infoList=新列表();
打破
}
返回信息列表;
}
…
}
验证 您可以使用以下测试类来验证其是否有效:

[TestClass]
公共类服务测试
{
[测试方法]
public void GetInfoList\u ShouldReturn\u ListCarInfo()
{
var service=newsomeservice();
var list=service.GetInfoList(1);
添加(新的CarInfo());
Assert.IsNotNull(列表);
Assert.AreEqual(1,list.Count);
}
笔记
  • 定义
    infoList
    时,需要将例如
    列表
    转换为
    列表
  • 您不需要将
    type
    作为参数传入,因为您可以根据
    t
    type参数(例如通过
    nameof(t)
    )来确定
  • 您不需要预先初始化
    infoList
    ,因为在大多数情况下,它会立即被替换为例如
    GetCarList()
    的结果
  • 如果这是一个作为可重用库的一部分的公共可用接口,那么您应该更喜欢返回
    集合
    ,而不是
    列表
    ()
  • 从设计的角度来看,我不喜欢硬编码的switch语句与初始化方法有1:1的关系,但如果没有进一步了解您的业务需求,我将保持现状
进一步优化 这与您最初的问题无关,但通过C#8.0的模式匹配,您可以稍微整理一下switch语句,以便:

public List GetInfoList(int-userId),其中T:BaseInfo=>
(T)开关的名称
{
nameof(CarInfo)=>GetCarList(userId)作为列表,
nameof(PetInfo)=>GetPetList(userId)作为列表,
_=>新列表()
};

您可能只需要一个泛型方法
List GetInfoList(…)
List GetInfoList(字符串类型,int userId),其中T:BaseInfo
将是正确的泛型签名,并且添加到@CamiloTerevinto reply,只要这些类型是BaseInfo,列表将能够保存其中的任何类型(即列表可以同时保存PetInfo和CarInfo)。将方法更改为建议的
public list GetInfoList(字符串类型,int userId)后其中T:BaseInfo
出现以下错误:
无法将type“System.Collections.Generic.List”隐式转换为“System.Collections.Generic.List”
无法将type“System.Collections.Generic.List”隐式转换为“System.Collections.Generic.List”
@因此,此处缺少的部分可能需要您进行修改提供从例如
列表
列表
的转换。您可能认为这是隐式的,但事实并非如此。此外,您不需要传入
字符串类型
;您可以通过例如
nameof(t)获得该转换
。我在下面的完整答案中扩展了Camilo的指导,并进行了单元测试以验证功能。但是……但是……如果有人在不同的名称空间中派生另一个名为
CarInfo
的类呢?如果只有两个选择,我会坚持使用if/else检查typeof……至少直到@pinkfloydx33:是的,当然是不重要的还有,谢谢你让我意识到这个建议;这是我一直想要的,尤其是在没有容器的情况下处理依赖注入。
 public interface ISomeService
 {
   List<ANY_OF_THE_DERIVED_CLASSES> GetInfoList(string type, int userId)
 }