T必须是具有公共无参数构造函数的非抽象类型,以便在泛型类型或方法中将其用作参数“TModel”

时间:2022-09-21 00:41:38

I've tried searching SO for the answer and stumbled upon similar problems but I couldn't manage to use them for solving my problem, so please try not to mark this as a duplicate. Let's move on to the real deal:

我已经尝试搜索SO以获得答案并偶然发现类似的问题,但我无法使用它们来解决我的问题,所以请尽量不要将其标记为重复。让我们继续谈谈真正的交易:

I have a generic library for standardizing entity framework database first models. These are the generic classes that I've created:

我有一个通用库,用于标准化实体框架数据库的第一个模型。这些是我创建的泛型类:

public abstract class GenericLookupModel : IActive, ICreated, IModified, IIdentity, IStringValue
{
    public bool is_active { get; set; }
    public string value { get; set; }
    public string description { get; set; }
    public DateTime created_on { get; set; }
    public string created_by { get; set; }
    public DateTime modified_on { get; set; }
    public string modified_by { get; set; }
    public int id {get;set;}

    public void SetCreated(string creator = "SYSTEM")
    {
        created_by = creator;
        created_on = DateTime.Now;
    }

    public void SetModified(string modifier = "SYSTEM")
    {
        modified_by = modifier;
        modified_on = DateTime.Now;
    }
}

And an class for the ViewModel with pre-set MVC attributes

并且ViewModel的类具有预先设置的MVC属性

public abstract class GenericLookupViewModel
{
    [Key]
    public int ID { get; set; }

    [Required]
    [StringLength(300)]
    public string Name { get; set; }

    [StringLength(4000)]
    public string Description { get; set; }

    [Required]
    public bool Active { get; set; }

    [StringLength(50)]
    [DisplayName("Record last modified by")]
    public string ModifiedBy { get; set; }

    [DisplayName("Record last modified Date")]
    [DataType(DataType.Date)]
    [DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)]
    public DateTime ModifiedOn { get; set; }

    [StringLength(50)]
    [DisplayName("Record created by")]
    public string CreatedBy { get; set; }

    [DisplayName("Record creation Date")]
    [DataType(DataType.Date)]
    [DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)]
    public DateTime CreatedOn { get; set; }
}

Also, I've created a service class that I intend to use inside the controller for getting the data:

另外,我已经创建了一个服务类,我打算在控制器中使用它来获取数据:

public abstract class GenericLookupModelDataService<TModel, TViewModel> : object 
    where TModel : GenericLookupModel, new()
    where TViewModel : GenericLookupViewModel, new()
{
    private readonly DbContext _db;

    private DbContext entities
    {
        get { return _db; }
    }

    public GenericLookupModelDataService()
    {
        _db =
            new DbContext(
                System.Configuration.ConfigurationManager.ConnectionStrings["DefaultConnectionString"].ConnectionString);
    }

    public virtual IEnumerable<TViewModel> ReadAllActive()
    {
        return entities.Set<TModel>().Where(x => x.is_active).Select(product => new TViewModel
        {
            ID = product.id,
            Active = product.is_active,
            Description = product.description,
            Name = product.value,
            CreatedBy = product.created_by,
            CreatedOn = product.created_on,
            ModifiedBy = product.modified_by,
            ModifiedOn = product.modified_on
        });
    }

    public virtual IEnumerable<TViewModel> Read()
    {
        return entities.Set<TModel>().Select(product => new TViewModel
        {
            ID = product.id,
            Active = product.is_active,
            Description = product.description,
            Name = product.value,
            CreatedBy = product.created_by,
            CreatedOn = product.created_on,
            ModifiedBy = product.modified_by,
            ModifiedOn = product.modified_on
        });
    }

    public virtual void Create(TViewModel product, string username = "SYSTEM")
    {
        var entity = new TModel
        {
            is_active = product.Active,
            description = product.Description,
            value = product.Name,
        };

        entity.SetCreated();
        entity.SetModified();

        _db.Set<TModel>().Add(entity);
        _db.SaveChanges();
    }

    public virtual void Update(TViewModel product, string username = "SYSTEM")
    {
        var entity = new TModel
        {
            id = product.ID,
            is_active = product.Active,
            description = product.Description,
            value = product.Name
        };
        entity.SetModified();


        _db.Set<TModel>().Attach(entity);
        entities.Entry(entity).State = EntityState.Modified;
        entities.SaveChanges();
    }

    public virtual void Destroy(TViewModel product)
    {
        var entity = new TModel {id = product.ID};

        entities.Set<TModel>().Attach(entity);
        entities.Set<TModel>().Remove(entity);
        entities.SaveChanges();
    }

    public virtual TViewModel GetByID(int ID)
    {
        var item = entities.Set<TModel>().Find(ID);
        var result = new TViewModel
        {
            ID = item.id,
            Active = item.is_active,
            CreatedBy = item.created_by,
            CreatedOn = item.created_on,
            Description = item.description,
            ModifiedBy = item.modified_by,
            ModifiedOn = item.modified_on,
            Name = item.value
        };
        return result;
    }

    public void Dispose()
    {
        entities.Dispose();
    }

}

The library compiles fine, I use it inside the data layer project inside my MVC App. Start off by creating a new view model:

库编译得很好,我在我的MVC App里面的数据层项目中使用它。首先创建一个新的视图模型:

public class RoleViewModel : GenericLookupViewModel
{


}

Then, lets create a service:

然后,让我们创建一个服务:

public class RoleService : GenericLookupModelDataService<tblkp_Role, RoleViewModel> 
{

}

Make the Entity Framework class inherit from the abstract model:

使Entity Framework类继承自抽象模型:

partial class tblkp_Role : GenericLookupModel
{

}

Finally let's create our controller:

最后让我们创建我们的控制器:

public class EmployeeController : Controller
{
    private RoleService roleService;

    public EmployeeController()
    {
        dataService = new EmployeeService();
        PopulateLookups();
    }

    private void PopulateLookups()
    {
        roleService = new RoleService();
        ViewData["roles"] = roleService.ReadAllActive();
    }

    public ActionResult Index()
    {
        return View();
    }

}

Sorry for the wall-of-code, some code has already been removed for brevity. While compiling it gives me 3 errors: T必须是具有公共无参数构造函数的非抽象类型,以便在泛型类型或方法中将其用作参数“TModel”

对于代码墙感到抱歉,为简洁起见,已删除了一些代码。编译它时给了我3个错误:

UPDATE: Provided tblk_Role class generated automatically by EF (DB First approach):

更新:提供由EF自动生成的tblk_Role类(DB First方法):

using System;
using System.Collections.Generic;

public partial class tblkp_Role
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public tblkp_Role()
    {
        this.tbl_Employee = new HashSet<tbl_Employee>();
    }

    public int id { get; set; }
    public string value { get; set; }
    public string desciption { get; set; }
    public bool is_active { get; set; }
    public System.DateTime created_on { get; set; }
    public string created_by { get; set; }
    public System.DateTime modified_on { get; set; }
    public string modified_by { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<tbl_Employee> tbl_Employee { get; set; }
}

UPDATE 2: Erros in plain text format:

更新2:纯文本格式的Erros:

Error 33 'DataLayer.Model.tblkp_Role' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'TModel' in the generic type or method 'MyLib.Model.GenericLookupModelDataService<TModel,TViewModel>' c:\Projects\Sources\MyLib\bin\Release\MyLib.dll

错误33'DataLayer.Model.tblkp_Role'必须是具有公共无参数构造函数的非抽象类型,以便在泛型类型或方法'MyLib.Model.GenericLookupModelDataService 'c中将其用作参数'TModel' :\项目\来源\ MyLib中\ BIN \发布\中是指mylib.dll ,tviewmodel>

Error 32 The type 'DataLayer.Model.tblkp_Role' cannot be used as type parameter 'TModel' in the generic type or method 'MyLib.Model.GenericLookupModelDataService<TModel,TViewModel>'. There is no boxing conversion from 'DataLayer.Model.tblkp_Role' to 'MyLib.Model.GenericLookupModel'. c:\Projects\Sources\MyLib\bin\Release\MyLib.dll

错误32类型'DataLayer.Model.tblkp_Role'不能用作泛型类型或方法'MyLib.Model.GenericLookupModelDataService '中的类型参数'TModel'。没有从'DataLayer.Model.tblkp_Role'到'MyLib.Model.GenericLookupModel'的装箱转换。 C:\项目\来源\ MyLib中\ BIN \发布\中是指mylib.dll ,tviewmodel>

2 个解决方案

#1


17  

You have the following:

你有以下几点:

public abstract class GenericLookupModelDataService<TModel, TViewModel> : object 
    where TModel : GenericLookupModel, new()
    where TViewModel : GenericLookupViewModel, new()
{
  // ...

That class has two generic paramters called TModel and TViewModel. Each of these has constraints to it, indicated after the where contextual keyword.

该类有两个名为TModel和TViewModel的通用参数。其中每个都有约束,在where contextual关键字后面指出。

For TModel the constraints are:

对于TModel,约束是:

  • a base class constraint requiring that the class GenericLookupModel must be a base class of what ever type is substituted in for TModel, and
  • 一个基类约束,要求类GenericLookupModel必须是TModel替换的类型的基类,并且
  • a constructor constraint new() requiring that the type used for TModel must expose a public instance constructor that takes zero arguments.
  • 构造函数约束new()要求用于TModel的类型必须公开一个接受零参数的公共实例构造函数。

One of the errors you ask about is:

您询问的其中一个错误是:

Error 33 'DataLayer.Model.tblkp_Role' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'TModel' in the generic type or method 'MyLib.Model.GenericLookupModelDataService<TModel,TViewModel>'

错误33'DataLayer.Model.tblkp_Role'必须是具有公共无参数构造函数的非抽象类型,以便在泛型类型或方法'MyLib.Model.GenericLookupModelDataService '中将其用作参数'TModel' ,tviewmodel>

This simply means that the type tblkp_Role which you try to use for TModel does not conform to the constructor constraint. Do you have the 0-parameter constructor?

这只是意味着您尝试用于TModel的类型tblkp_Role不符合构造函数约束。你有0参数构造函数吗?

Another error you ask about is:

您询问的另一个错误是:

Error 32 The type 'DataLayer.Model.tblkp_Role' cannot be used as type parameter 'TModel' in the generic type or method 'MyLib.Model.GenericLookupModelDataService<TModel,TViewModel>'. There is no boxing conversion from 'DataLayer.Model.tblkp_Role' to 'MyLib.Model.GenericLookupModel'.

错误32类型'DataLayer.Model.tblkp_Role'不能用作泛型类型或方法'MyLib.Model.GenericLookupModelDataService '中的类型参数'TModel'。没有从'DataLayer.Model.tblkp_Role'到'MyLib.Model.GenericLookupModel'的装箱转换。 ,tviewmodel>

This indicates that the base class constraint is not met. Since the error text talks about "boxing conversion", it appears that the type tblkp_Role which the compiler is using, is in fact a value type (struct type, or enum type). Types like that can never derive from GenericLookupModel as the constraint requires.

这表示不满足基类约束。由于错误文本讨论了“装箱转换”,因此看起来编译器正在使用的类型tblkp_Role实际上是值类型(结构类型或枚举类型)。类似的类型永远不能从约束所需的GenericLookupModel派生。

It must be that the type tblkp_Role that the C# compiler uses, is another type than the type you define with partial class tblkp_Role : GenericLookupModel. You may have some conflicting names or some duplicate code/names from referenced projects.

必须是C#编译器使用的类型tblkp_Role,是使用部分类tblkp_Role定义的类型的另一种类型:GenericLookupModel。您可能在引用的项目中有一些冲突的名称或一些重复的代码/名称。

In the image version of your compile-time errors we see that the compiler also complains that the type tblkp_Role which you use is declared in an assembly which you have no reference to. Try fixing that one first. Maybe the other ones will go away once the compiler can see all details of tblkp_Role because it has the reference to the project that defines that type.

在编译时错误的映像版本中,我们看到编译器还抱怨您使用的类型tblkp_Role是在您没有引用的程序集中声明的。先尝试修复那个。一旦编译器可以看到tblkp_Role的所有细节,其他的将会消失,因为它具有对定义该类型的项目的引用。

#2


2  

The error you mentioned is usually faced when you try to use the same generic type parameter in different classes without defining all the constraints in at least one of them. See this Jon Skeet's answer for clarity.

当您尝试在不同的类中使用相同的泛型类型参数而不在其中至少一个中定义所有约束时,通常会遇到您提到的错误。为清楚起见,请参阅Jon Skeet的回答。

But you are using TModel in only one class here i.e. GenericLookupModelDataService, therefore I tried the following:

但是你只在一个类中使用TModel,即GenericLookupModelDataService,因此我尝试了以下方法:

I wrote all your code in the same code file that means no external library. Something like this:

我在同一个代码文件中编写了所有代码,这意味着没有外部库。像这样的东西:

class Program
{
    static void Main(string[] args)
    {
        RoleService roleService = new RoleService();
    }
}

class RoleService : GenericLookupModelDataService<tblkp_Role, RoleViewModel> 
{ }

public abstract class GenericLookupModelDataService<TModel, TViewModel> : object
    where TModel : GenericLookupModel, new()
    where TViewModel : GenericLookupViewModel, new()
{ }

public abstract class GenericLookupViewModel { }

public abstract class GenericLookupModel { }

public class RoleViewModel : GenericLookupViewModel { }

public partial class tblkp_Role : GenericLookupModel 
{
}

public partial class tblkp_Role
{
    public tblkp_Role()
    {

    }
}

This compiles successfully. Therefore I suspect that compiler is unaware of the full definition of tblkp_Role.

这成功编译。因此我怀疑编译器不知道tblkp_Role的完整定义。

I would suggest re building the library and re-referencing it again (Also check the reference path to ensure you are not mistakenly referencing older version).

我建议重新构建库并再次重新引用它(同时检查引用路径以确保您没有错误地引用旧版本)。

I have faced similar issues with partial classes which are automatically created by EF in DB first approach specifically when I tried to define metadata classes.

我遇到了部分类的类似问题,这些问题是由我在数据库第一种方法中自动创建的,当我尝试定义元数据类时。

#1


17  

You have the following:

你有以下几点:

public abstract class GenericLookupModelDataService<TModel, TViewModel> : object 
    where TModel : GenericLookupModel, new()
    where TViewModel : GenericLookupViewModel, new()
{
  // ...

That class has two generic paramters called TModel and TViewModel. Each of these has constraints to it, indicated after the where contextual keyword.

该类有两个名为TModel和TViewModel的通用参数。其中每个都有约束,在where contextual关键字后面指出。

For TModel the constraints are:

对于TModel,约束是:

  • a base class constraint requiring that the class GenericLookupModel must be a base class of what ever type is substituted in for TModel, and
  • 一个基类约束,要求类GenericLookupModel必须是TModel替换的类型的基类,并且
  • a constructor constraint new() requiring that the type used for TModel must expose a public instance constructor that takes zero arguments.
  • 构造函数约束new()要求用于TModel的类型必须公开一个接受零参数的公共实例构造函数。

One of the errors you ask about is:

您询问的其中一个错误是:

Error 33 'DataLayer.Model.tblkp_Role' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'TModel' in the generic type or method 'MyLib.Model.GenericLookupModelDataService<TModel,TViewModel>'

错误33'DataLayer.Model.tblkp_Role'必须是具有公共无参数构造函数的非抽象类型,以便在泛型类型或方法'MyLib.Model.GenericLookupModelDataService '中将其用作参数'TModel' ,tviewmodel>

This simply means that the type tblkp_Role which you try to use for TModel does not conform to the constructor constraint. Do you have the 0-parameter constructor?

这只是意味着您尝试用于TModel的类型tblkp_Role不符合构造函数约束。你有0参数构造函数吗?

Another error you ask about is:

您询问的另一个错误是:

Error 32 The type 'DataLayer.Model.tblkp_Role' cannot be used as type parameter 'TModel' in the generic type or method 'MyLib.Model.GenericLookupModelDataService<TModel,TViewModel>'. There is no boxing conversion from 'DataLayer.Model.tblkp_Role' to 'MyLib.Model.GenericLookupModel'.

错误32类型'DataLayer.Model.tblkp_Role'不能用作泛型类型或方法'MyLib.Model.GenericLookupModelDataService '中的类型参数'TModel'。没有从'DataLayer.Model.tblkp_Role'到'MyLib.Model.GenericLookupModel'的装箱转换。 ,tviewmodel>

This indicates that the base class constraint is not met. Since the error text talks about "boxing conversion", it appears that the type tblkp_Role which the compiler is using, is in fact a value type (struct type, or enum type). Types like that can never derive from GenericLookupModel as the constraint requires.

这表示不满足基类约束。由于错误文本讨论了“装箱转换”,因此看起来编译器正在使用的类型tblkp_Role实际上是值类型(结构类型或枚举类型)。类似的类型永远不能从约束所需的GenericLookupModel派生。

It must be that the type tblkp_Role that the C# compiler uses, is another type than the type you define with partial class tblkp_Role : GenericLookupModel. You may have some conflicting names or some duplicate code/names from referenced projects.

必须是C#编译器使用的类型tblkp_Role,是使用部分类tblkp_Role定义的类型的另一种类型:GenericLookupModel。您可能在引用的项目中有一些冲突的名称或一些重复的代码/名称。

In the image version of your compile-time errors we see that the compiler also complains that the type tblkp_Role which you use is declared in an assembly which you have no reference to. Try fixing that one first. Maybe the other ones will go away once the compiler can see all details of tblkp_Role because it has the reference to the project that defines that type.

在编译时错误的映像版本中,我们看到编译器还抱怨您使用的类型tblkp_Role是在您没有引用的程序集中声明的。先尝试修复那个。一旦编译器可以看到tblkp_Role的所有细节,其他的将会消失,因为它具有对定义该类型的项目的引用。

#2


2  

The error you mentioned is usually faced when you try to use the same generic type parameter in different classes without defining all the constraints in at least one of them. See this Jon Skeet's answer for clarity.

当您尝试在不同的类中使用相同的泛型类型参数而不在其中至少一个中定义所有约束时,通常会遇到您提到的错误。为清楚起见,请参阅Jon Skeet的回答。

But you are using TModel in only one class here i.e. GenericLookupModelDataService, therefore I tried the following:

但是你只在一个类中使用TModel,即GenericLookupModelDataService,因此我尝试了以下方法:

I wrote all your code in the same code file that means no external library. Something like this:

我在同一个代码文件中编写了所有代码,这意味着没有外部库。像这样的东西:

class Program
{
    static void Main(string[] args)
    {
        RoleService roleService = new RoleService();
    }
}

class RoleService : GenericLookupModelDataService<tblkp_Role, RoleViewModel> 
{ }

public abstract class GenericLookupModelDataService<TModel, TViewModel> : object
    where TModel : GenericLookupModel, new()
    where TViewModel : GenericLookupViewModel, new()
{ }

public abstract class GenericLookupViewModel { }

public abstract class GenericLookupModel { }

public class RoleViewModel : GenericLookupViewModel { }

public partial class tblkp_Role : GenericLookupModel 
{
}

public partial class tblkp_Role
{
    public tblkp_Role()
    {

    }
}

This compiles successfully. Therefore I suspect that compiler is unaware of the full definition of tblkp_Role.

这成功编译。因此我怀疑编译器不知道tblkp_Role的完整定义。

I would suggest re building the library and re-referencing it again (Also check the reference path to ensure you are not mistakenly referencing older version).

我建议重新构建库并再次重新引用它(同时检查引用路径以确保您没有错误地引用旧版本)。

I have faced similar issues with partial classes which are automatically created by EF in DB first approach specifically when I tried to define metadata classes.

我遇到了部分类的类似问题,这些问题是由我在数据库第一种方法中自动创建的,当我尝试定义元数据类时。