将具体类型转换为嵌套通用基类型

时间:2017-04-12 19:27:39

标签: c# generics c#-4.0

假设我已经嵌套了类似于以下内容的通用数据类:

public class BaseRecordList<TRecord, TUserInfo>
    where TRecord : BaseRecord<TUserInfo>
    where TUserInfo : BaseUserInfo
{
    public virtual IList<TRecord> Records { get; set; }
    public virtual int Limit { get; set; }
}

public class BaseRecord<TUserInfo>
    where TUserInfo : BaseUserInfo
{
    public virtual DateTime CreationTime { get; set; }
    public virtual TUserInfo UserInfo { get; set; }
}

public class BaseUserInfo
{
    public virtual string Name { get; set; }
    public virtual int Age { get; set; }
}

有两个具体的版本:

// Project 1: Requires some extra properties
public class Project1RecordList : BaseRecordList<Project1Record, Project1UserInfo> {}

public class Project1Record : BaseRecord<Project1UserInfo>
{
    public Guid Version { get; set; }
}

public class Project1UserInfo : BaseUserInfo
{
    public string FavouriteFood { get; set; }
}

// Project 2: Some properties need alternate names for JSON serialization
public class Project2RecordList : BaseRecordList<Project2Record, Project2UserInfo>
{
    [JsonProperty("allRecords")]
    public override IList<Project2Record> Records { get; set; }
}

public class Project2Record : BaseRecord<Project2UserInfo> {}

public class Project2UserInfo : BaseUserInfo
{
    [JsonProperty("username")]
    public override string Name { get; set; }
}

我很高兴有2个存储库分别返回Project1RecordList和Project2RecordList,但在我的代码中的某些时候,我发现自己需要能够在一个地方处理这两个。我认为在这一点上我需要能够将这两种类型视为

BaseRecordList<BaseRecord<BaseUserInfo>, BaseUserInfo>

因为这是满足通用约束所需的最低要求,但是尝试使用&#34;作为&#34;抛出关于无法转换的错误。

有没有办法做到这一点,甚至是一种更理智的方式来处理这种情况而没有大量的代码重复?如果它对Web应用程序产生任何影响,并且已经存在大量数据类,其中许多使用这些嵌套泛型。

1 个答案:

答案 0 :(得分:3)

你所说的是协方差,MSDN在这里有一篇很好的文章:https://msdn.microsoft.com/en-us/library/dd799517(v=vs.110).aspx

首先,创建一个新界面:

interface IBaseRecord<out TUserInfo>
  where TUserInfo : BaseUserInfo
{
}

让BaseRecord继承新界面:

public class BaseRecord<TUserInfo> : IBaseRecord<TUserInfo>
    where TUserInfo : BaseUserInfo
{
    public virtual DateTime CreationTime { get; set; }
    public virtual TUserInfo UserInfo { get; set; }
}

如果做得好,这应该编译:

IBaseRecord<BaseUserInfo> project1 = new Project1Record();
IBaseRecord<BaseUserInfo> project2 = new Project2Record();

要将其扩展为BaseRecordList,请创建IBaseRecordList:

interface IBaseRecordList<out TRecord, out TUserInfo>
  where TRecord : IBaseRecord<TUserInfo>
  where TUserInfo : BaseUserInfo
{
}

让BaseRecordList继承自:

public class BaseRecordList<TRecord, TUserInfo> : IBaseRecordList<TRecord, TUserInfo>

然后使用:

IBaseRecordList<IBaseRecord<BaseUserInfo>, BaseUserInfo> project1 = new Project1RecordList();
IBaseRecordList<IBaseRecord<BaseUserInfo>, BaseUserInfo> project2 = new Project2RecordList();

完成设置后,只需将通用的所有属性或功能添加到接口即可。