web-dev-qa-db-ja.com

Tは、ジェネリック型またはメソッドのパラメーター 'TModel'として使用するために、パラメーターなしのパブリックコンストラクターを持つ非抽象型である必要があります

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

そして、事前に設定されたMVC属性を持つViewModelのクラス

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アプリ内のデータレイヤープロジェクト内で使用します。新しいビューモデルを作成することから始めます。

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つのエラーが発生します: enter image description here

[〜#〜] update [〜#〜]: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:プレーンテキスト形式のエラー:

エラー33 'DataLayer.Model.tblkp_Role'は、ジェネリック型またはメソッド 'MyLib.Model.GenericLookupModelDataService <TModel、TViewModel>' cでパラメーター 'TModel'として使用するには、パラメーターなしのパブリックコンストラクターを持つ非抽象型である必要があります。 :\ Projects\Sources\MyLib\bin\Release\MyLib.dll

エラー32型 'DataLayer.Model.tblkp_Role'は、ジェネリック型またはメソッド 'MyLib.Model.GenericLookupModelDataService <TModel、TViewModel>'の型パラメーター 'TModel'として使用できません。 「DataLayer.Model.tblkp_Role」から「MyLib.Model.GenericLookupModel」へのボクシング変換はありません。 c:\ Projects\Sources\MyLib\bin\Release\MyLib.dll

12
Adrian K.

次のものがあります。

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

そのクラスには、TModelおよびTViewModelという2つの汎用パラメーターがあります。これらのそれぞれにconstraintsがあり、whereコンテキストキーワードの後に​​示されます。

TModelの場合、制約は次のとおりです。

  • クラスGenericLookupModelTModelに代入されるすべての型の基本クラスでなければならないことを要求する基本クラス制約
  • コンストラクター制約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_で定義した型とは別の型である必要があります。参照されているプロジェクトから、名前が競合しているか、コード/名前が重複している可能性があります。

コンパイル時エラーのイメージバージョンでは、コンパイラが、使用する型_tblkp_Role_が参照のないアセンブリで宣言されていることも報告していることがわかります。最初に修正してみてください。コンパイラが_tblkp_Role_のすべての詳細を確認できるようになると、そのタイプを定義するプロジェクトへの参照が含まれているため、他のものはなくなるでしょう。

22

言及したエラーは通常、少なくとも1つのクラスですべての制約を定義せずに、異なるクラスで同じジェネリック型パラメーターを使用しようとすると発生します。明確にするために this Jon Skeetの回答を参照してください。

しかし、ここでは1つのクラス、つまりGenericLookupModelDataServiceでのみTModelを使用しているため、以下を試しました。

私はすべてのコードを同じコードファイルに書き込んだので、外部ライブラリはありません。このようなもの:

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の完全な定義を認識していないと思います。

ライブラリを再構築して再度参照することをお勧めします(参照パスを確認して、古いバージョンを誤って参照していないことを確認してください)。

特にメタデータクラスを定義しようとしたときに、DBの最初のアプローチでEFによって自動的に作成される部分クラスで同様の問題に直面しました。

3
Rachit Pandey