簡體   English   中英

T必須是具有公共無參數構造函數的非抽象類型,以便在泛型類型或方法中將其用作參數“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以獲得答案並偶然發現類似的問題,但我無法使用它們來解決我的問題,所以請盡量不要將其標記為重復。 讓我們繼續談談真正的交易:

我有一個通用庫,用於標准化實體框架數據庫的第一個模型。 這些是我創建的泛型類:

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;
    }
}

並且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; }
}

另外,我已經創建了一個服務類,我打算在控制器中使用它來獲取數據:

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 App里面的數據層項目中使用它。 首先創建一個新的視圖模型:

public class RoleViewModel : GenericLookupViewModel
{


}

然后,讓我們創建一個服務:

public class RoleService : GenericLookupModelDataService<tblkp_Role, RoleViewModel> 
{

}

使Entity Framework類繼承自抽象模型:

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();
    }

}

對於代碼牆感到抱歉,為簡潔起見,已刪除了一些代碼。 編譯它時給了我3個錯誤: 在此輸入圖像描述

更新 :提供由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; }
}

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

錯誤33'DataLayer.Model.tblkp_Role'必須是具有公共無參數構造函數的非抽象類型,以便在泛型類型或方法'MyLib.Model.GenericLookupModelDataService <TModel,TViewModel>'c中將其用作參數'TModel' :\\項目\\來源\\ MyLib中\\ BIN \\發布\\中是指mylib.dll

錯誤32類型'DataLayer.Model.tblkp_Role'不能用作泛型類型或方法'MyLib.Model.GenericLookupModelDataService <TModel,TViewModel>'中的類型參數'TModel'。 沒有從'DataLayer.Model.tblkp_Role'到'MyLib.Model.GenericLookupModel'的裝箱轉換。 C:\\項目\\來源\\ MyLib中\\ BIN \\發布\\中是指mylib.dll

你有以下幾點:

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

該類有兩個名為TModelTViewModel通用參數。 其中每個都有對它的約束 ,在where contextual關鍵字后面指出。

對於TModel ,約束是:

  • 一個基類約束,要求類GenericLookupModel必須是TModel替換的類型的基類,並且
  • 構造函數約束new()要求用於TModel的類型必須公開一個接受零參數的public實例構造函數。

你問的一個錯誤是:

錯誤33'DataLayer.Model.tblkp_Role'必須是具有公共無參數構造函數的非抽象類型,才能在泛型類型或方法'MyLib.Model.GenericLookupModelDataService <TModel,TViewModel>'中將其用作參數'TModel'

這只是意味着您嘗試用於TModel的類型tblkp_Role不符合構造函數約束。 你有0參數構造函數嗎?

您詢問的另一個錯誤是:

錯誤32類型'DataLayer.Model.tblkp_Role'不能用作泛型類型或方法'MyLib.Model.GenericLookupModelDataService <TModel,TViewModel>'中的類型參數'TModel'。 沒有從'DataLayer.Model.tblkp_Role'到'MyLib.Model.GenericLookupModel'的裝箱轉換。

這表示不滿足基類約束。 由於錯誤文本討論了“裝箱轉換”,因此看起來編譯器正在使用的類型tblkp_Role實際上是值類型( struct類型或enum類型)。 類似的類型永遠不能從約束所需的GenericLookupModel派生。

必須是C#編譯器使用的類型tblkp_Role ,是使用partial class tblkp_Role : GenericLookupModel定義的類型的另一種類型partial class tblkp_Role : GenericLookupModel 您可能在引用的項目中有一些沖突的名稱或一些重復的代碼/名稱。

在編譯時錯誤的映像版本中,我們看到編譯器還抱怨您使用的類型tblkp_Role是在您沒有引用的程序tblkp_Role聲明的。 先嘗試修復那個。 一旦編譯器可以看到tblkp_Role所有細節,其他的將會消失,因為它具有對定義該類型的項目的引用。

當您嘗試在不同的類中使用相同的泛型類型參數而不在其中至少一個中定義所有約束時,通常會遇到您提到的錯誤。 請參見喬恩斯基特對清晰的答案。

但是你只在一個類中使用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的完整定義。

我建議重新構建庫並再次重新引用它(同時檢查引用路徑以確保您沒有錯誤地引用舊版本)。

我遇到了部分類的類似問題,這些問題是由我在數據庫第一種方法中自動創建的,當我嘗試定義元數據類時。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM