Search code examples
c#genericsnested-generics

CS0311 - Inherited Generics & where Constraints


I am currently experiencing the following error:

The type 'WebScraperTaskModel' cannot be used as type parameter 'DataModel' in the generic type or method 'Reports<ReportClass, DataModel, StrategyEnum, ResultEnum>'. There is no implicit reference conversion from 'WebScraperTaskModel' to 'WebScraperTaskModel>'.*

I have met the constraints of DataModel by specifying: WebScraperWorkload : Serialize<WebScraperWorkload>

Therefore the reason why I'm getting this error is completely perplexing. Would love any insights anyone may have.

class ProductAvailability : Reports<ProductAvailability, WebScraperTaskModel, ProductAvailabilityStrategyEnum, ProductAvailabilityResultEnum>
{ } // Error is Occurring Here

abstract class Reports<ReportClass, DataModel, StrategyEnum, ResultEnum>
    where ReportClass: Reports<ReportClass, DataModel, StrategyEnum, ResultEnum>, new()
    where DataModel: Serialize<DataModel>, new()
    where StrategyEnum : struct, IConvertible
    where ResultEnum : struct, IConvertible
{
    protected abstract void GenerateReport(); 
    protected abstract Func<ResultEnum?> StrategyHandler(StrategyEnum strategy);
    protected abstract Dictionary<StrategyEnum, List<string>> StrategyMapping { get; }   

    public static void Configure()
    {
        var formDE = new frmDataEntry();
        var dataModel = new DataModel();
        (var data, var ex) = dataModel.Fetch();
        formDE.dtaMain.DataSource = data;
    }

}

[Serializable]
class WebScraperWorkload : Serialize<WebScraperWorkload>
{
    public List<WebScraperTaskModel> Workload { get; set; }

    protected override Enum[] Namespace => new Enum[] { ConsiderationEnum.Database, AreaEnum.Reporting, ReportingEnum.ProductAvailability };
}

abstract class Serialize<DataModel>
    where DataModel : class
{
    protected abstract Enum[] Namespace { get; }

    public (DataModel? Result, Exception Exception) Fetch()
    { }  //Left Out For Brevity

    public (bool Success, Exception Exception) Save()
    { }  //Left Out For Brevity

}

Solution

  • You have to declare both generic type parameters - the derived and the underlying DataModel for Serialize constraint to work :

    class ProductAvailability : Reports<ProductAvailability, WebScraperWorkload, WebScraperTaskModel>
    {
        protected override void GenerateReport()
        {
            throw new NotImplementedException();
        }
    }
    
    abstract class Reports<ReportClass, SerializeDataModel, DataModel>
        where ReportClass : Reports<ReportClass, SerializeDataModel, DataModel>, new()
        where SerializeDataModel : Serialize<DataModel>, new()
        where DataModel : class, new()
    {
    
        protected abstract void GenerateReport();
    
        public static void Configure()
        {
            var dataModel = new SerializeDataModel();
            (var data, var ex) = dataModel.Fetch();
        }
    }
    
    class WebScraperWorkload : Serialize<WebScraperTaskModel>
    {
        protected override Enum[] Namespace => new Enum[0];
    }
    
    abstract class Serialize<DataModel> where DataModel : class
    {
        public List<DataModel> Workload { get; set; }
    
        protected abstract Enum[] Namespace { get; }
    
        public (DataModel? Result, Exception Exception) Fetch() => default;
    
        public (bool Success, Exception Exception) Save() => default;
    }
    
    public class WebScraperTaskModel { }
    

    PS. assuming this is typo :

    class WebScraperWorkload : Serialize<WebScraperWorkload>