T 必须是具有 public 无参数构造函数的 non-abstract 类型,以便将其用作泛型类型或方法中的参数 'TModel'
T 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
我尝试在 SO 中搜索答案并偶然发现了类似的问题,但我无法使用它们来解决我的问题,所以请尽量不要将其标记为重复。让我们继续进行真正的交易:
我有一个用于标准化 entity framework 数据库优先模型的通用库。
这些是我创建的通用 classes:
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;
}
}
以及具有 pre-set MVC 属性的 ViewModel 的 class
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; }
}
此外,我创建了一个服务 class,我打算在控制器内部使用它来获取数据:
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();
}
}
该库编译良好,我在我的 MVC 应用程序的数据层项目中使用它。从创建一个新的视图模型开始:
public class RoleViewModel : GenericLookupViewModel
{
}
然后,让我们创建一个服务:
public class RoleService : GenericLookupModelDataService<tblkp_Role, RoleViewModel>
{
}
使Entity Frameworkclass继承抽象模型:
partial class tblkp_Role : GenericLookupModel
{
}
最后让我们创建我们的控制器:
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();
}
}
抱歉 wall-of-code,为简洁起见,一些代码已被删除。
编译时出现 3 个错误:
UPDATE:前提是 tblk_Role class 由 EF(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; }
}
更新 2:纯文本格式的错误:
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
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
您有以下内容:
public abstract class GenericLookupModelDataService<TModel, TViewModel> : object
where TModel : GenericLookupModel, new()
where TViewModel : GenericLookupViewModel, new()
{
// ...
class 有两个通用参数,称为 TModel
和 TViewModel
。这些中的每一个都有 constraints,在 where
上下文关键字之后指示。
对于TModel
,约束是:
- 一个基本 class 约束,要求 class
GenericLookupModel
必须是 TModel
所替换的任何类型的基本 class,并且
- 构造函数约束
new()
要求用于 TModel
的类型必须公开一个采用零参数的 public
实例构造函数。
您询问的其中一个错误是:
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>'
这只是意味着您尝试用于 TModel
的类型 tblkp_Role
不符合构造函数约束。你有0参数的构造函数吗?
您询问的另一个错误是:
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'.
这表示不满足基本 class 约束。由于错误文本谈到 "boxing conversion",编译器使用的类型 tblkp_Role
似乎实际上是值类型(struct
类型或 enum
类型) .像这样的类型永远不能根据约束要求从 GenericLookupModel
派生。
肯定是 C# 编译器使用的类型 tblkp_Role
与您用 partial class tblkp_Role : GenericLookupModel
定义的类型不同。您可能有一些冲突的名称或一些来自引用项目的重复 code/names。
在您的 compile-time 错误的图像版本中,我们看到编译器还抱怨您使用的类型 tblkp_Role
是在您没有引用的程序集中声明的。尝试先修复那个。也许一旦编译器可以看到 tblkp_Role
的所有细节,其他的就会消失,因为它具有对定义该类型的项目的引用。
当您尝试在不同的 class 中使用相同的泛型类型参数而不至少在其中一个中定义所有约束时,通常会遇到您提到的错误。为清楚起见,请参阅 this Jon Skeet 的回答。
但是您在这里只在一个 class 中使用 TModel,即 GenericLookupModelDataService,因此我尝试了以下操作:
我把你所有的代码都写在同一个代码文件中,这意味着没有外部库。像这样:
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()
{
}
}
编译成功。
因此我怀疑编译器不知道 tblkp_Role.
的完整定义
我建议重新构建库并再次 re-referencing(同时检查引用路径以确保您没有错误地引用旧版本)。
我遇到了部分 classes 的类似问题,这些问题是由 EF 在 DB 优先方法中自动创建的,特别是当我尝试定义元数据 classes 时。
我尝试在 SO 中搜索答案并偶然发现了类似的问题,但我无法使用它们来解决我的问题,所以请尽量不要将其标记为重复。让我们继续进行真正的交易:
我有一个用于标准化 entity framework 数据库优先模型的通用库。 这些是我创建的通用 classes:
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;
}
}
以及具有 pre-set MVC 属性的 ViewModel 的 class
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; }
}
此外,我创建了一个服务 class,我打算在控制器内部使用它来获取数据:
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();
}
}
该库编译良好,我在我的 MVC 应用程序的数据层项目中使用它。从创建一个新的视图模型开始:
public class RoleViewModel : GenericLookupViewModel
{
}
然后,让我们创建一个服务:
public class RoleService : GenericLookupModelDataService<tblkp_Role, RoleViewModel>
{
}
使Entity Frameworkclass继承抽象模型:
partial class tblkp_Role : GenericLookupModel
{
}
最后让我们创建我们的控制器:
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();
}
}
抱歉 wall-of-code,为简洁起见,一些代码已被删除。
编译时出现 3 个错误:
UPDATE:前提是 tblk_Role class 由 EF(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; }
}
更新 2:纯文本格式的错误:
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
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
您有以下内容:
public abstract class GenericLookupModelDataService<TModel, TViewModel> : object
where TModel : GenericLookupModel, new()
where TViewModel : GenericLookupViewModel, new()
{
// ...
class 有两个通用参数,称为 TModel
和 TViewModel
。这些中的每一个都有 constraints,在 where
上下文关键字之后指示。
对于TModel
,约束是:
- 一个基本 class 约束,要求 class
GenericLookupModel
必须是TModel
所替换的任何类型的基本 class,并且 - 构造函数约束
new()
要求用于TModel
的类型必须公开一个采用零参数的public
实例构造函数。
您询问的其中一个错误是:
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>'
这只是意味着您尝试用于 TModel
的类型 tblkp_Role
不符合构造函数约束。你有0参数的构造函数吗?
您询问的另一个错误是:
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'.
这表示不满足基本 class 约束。由于错误文本谈到 "boxing conversion",编译器使用的类型 tblkp_Role
似乎实际上是值类型(struct
类型或 enum
类型) .像这样的类型永远不能根据约束要求从 GenericLookupModel
派生。
肯定是 C# 编译器使用的类型 tblkp_Role
与您用 partial class tblkp_Role : GenericLookupModel
定义的类型不同。您可能有一些冲突的名称或一些来自引用项目的重复 code/names。
在您的 compile-time 错误的图像版本中,我们看到编译器还抱怨您使用的类型 tblkp_Role
是在您没有引用的程序集中声明的。尝试先修复那个。也许一旦编译器可以看到 tblkp_Role
的所有细节,其他的就会消失,因为它具有对定义该类型的项目的引用。
当您尝试在不同的 class 中使用相同的泛型类型参数而不至少在其中一个中定义所有约束时,通常会遇到您提到的错误。为清楚起见,请参阅 this Jon Skeet 的回答。
但是您在这里只在一个 class 中使用 TModel,即 GenericLookupModelDataService,因此我尝试了以下操作:
我把你所有的代码都写在同一个代码文件中,这意味着没有外部库。像这样:
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()
{
}
}
编译成功。 因此我怀疑编译器不知道 tblkp_Role.
的完整定义我建议重新构建库并再次 re-referencing(同时检查引用路径以确保您没有错误地引用旧版本)。
我遇到了部分 classes 的类似问题,这些问题是由 EF 在 DB 优先方法中自动创建的,特别是当我尝试定义元数据 classes 时。