如何在Razor Pages页面模型中使用泛型类型?
解决方案
你遇到的编译失败是因为C#默认不支持泛型类型的逆变/协变转换,除非显式声明,以下是三种可落地的实现方案:
方案1:使用协变接口(最推荐,保留强类型特性)
首先定义带协变声明的泛型接口,把布局需要调用的所有属性、方法都定义在接口中:
// out关键字声明类型参数支持协变 public interface IFormPageModel<out TRead, out TWrite> where TRead : IReadEntity where TWrite : IWriteEntity { TRead ReadModel { get; } TWrite WriteModel { get; } string FormTitle { get; } // 其他布局需要用到的方法声明 }
让你的泛型基类实现该接口:
public class FormPageModel<ReadEntity, WriteEntity> : IFormPageModel<ReadEntity, WriteEntity> where ReadEntity : class, IReadEntity, new() where WriteEntity : class, IWriteEntity, new() { // 实现接口属性即可,原有逻辑无需修改 public ReadEntity ReadModel { get; set; } = new(); public WriteEntity WriteModel { get; set; } = new(); public string FormTitle { get; set; } }
最后修改FormLayout.cshtml的Model声明:
@model IFormPageModel<IReadEntity, IWriteEntity>
协变特性允许将IFormPageModel<具体实现类, 具体实现类>的实例自动转换为IFormPageModel<IReadEntity, IWriteEntity>类型,编译直接通过。
方案2:抽离非泛型基类(兼容性最好,适用于所有.NET版本)
把布局需要用到的公共逻辑抽离到非泛型抽象基类:
public abstract class FormPageModelBase { public abstract IReadEntity ReadModel { get; } public abstract IWriteEntity WriteModel { get; } public string FormTitle { get; set; } // 其他布局需要的公共方法 }
让你的泛型基类继承该非泛型基类:
public class FormPageModel<ReadEntity, WriteEntity> : FormPageModelBase where ReadEntity : class, IReadEntity, new() where WriteEntity : class, IWriteEntity, new() { public ReadEntity ReadModel { get; set; } = new(); public WriteEntity WriteModel { get; set; } = new(); // 实现基类抽象属性 public override IReadEntity ReadModel => ReadModel; public override IWriteEntity WriteModel => WriteModel; }
布局直接声明非泛型基类为Model即可:
@model FormPageModelBase
方案3:布局声明泛型参数(适用于.NET 6+,需要保留具体泛型类型的场景)
如果你的布局需要用到泛型的具体类型特性,可以直接给布局声明泛型参数,修改FormLayout.cshtml:
@typeparam TRead where TRead : class, IReadEntity, new() @typeparam TWrite where TWrite : class, IWriteEntity, new() @model FormPageModel<TRead, TWrite>
子页面引用该布局时会自动推断泛型类型,无需额外传参:
@page @model FormPageModel<自定义读实体, 自定义写实体> @{ Layout = "FormLayout.cshtml"; }
内容的提问来源于stack exchange,提问作者Ali EXE
相关产品推荐
相关产品推荐

