【问题标题】:Using generics and implement optional fields in an interface or implement an interface optionally?使用泛型并在接口中实现可选字段或可选地实现接口?
【发布时间】:2017-01-13 21:54:36
【问题描述】:

我正在使用C# 6.NET 4.6.2

我使用通用存储库和通用ASP.NET MVC Controller,因为我有很多查找表,不想为每个表创建单独的控制器和存储库

这是我的代码简化:

型号:

public interface IEntity
{
    int Id { get; set; }

}

public class Lookup1:IEntity
{

    public int Id { get; set; }

    public string Lookup1Name { get; set; }

    public string CreatedBy { get; set; }

    public DateTime CreatedDate { get; set; }
}
public class Lookup2:IEntity
{

    public int Id { get; set; }

    public string Lookup2Name { get; set; }

}

存储库:

public interface IGenericRepository<TEntity> where TEntity : class, IEntity
{
    void Update(TEntity obj);
}


public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class, IEntity
{
    public void  Update(TEntity obj)
    {
        table.Attach(obj);
        _db.Entry(obj).State = EntityState.Modified;
    }
}

通用控制器:

 public abstract class GenericController<TModel> : Controller
    where TModel : class,IEntity
{

    private IGenericRepository<TModel> _repository;

    [HttpPost]
    public async Task<IActionResult> Edit(TModel model)
    {
        try
        {
            if (ModelState.IsValid) { 
                _repository.Update(model);
                await _repository.Save();
            }
        }
        catch (Exception)
        {
            ModelState.AddModelError(string.Empty, "Unable to save changes.");
        }
        return View(model);
    }

控制器:

public class Lookup1Controller : GenericController<Lookup1>
{
    private IGenericRepository<Lookup1> _repository;

    public Lookup1Controller (IGenericRepository<Lookup1> repository) : base(repository)
    {
        _repository = repository;
    }
}

public class Lookup2Controller : GenericController<Lookup2>
{
    private IGenericRepository<Lookup2> _repository;

    public Lookup2Controller (IGenericRepository<Lookup2> repository) : base(repository)
    {
        _repository = repository;
    }
}

以上内容有效并更新了从我的 MVC 视图 .cshtml 文件传递​​的所有 Lookup1,Lookup2 模型字段。

但是,我的一些模型只有 DateCreatedCreatedBy 属性,我也想在我的通用控制器的 Edit 方法中更新这些属性。

类似的东西

 model.DateCreated = DateTime.Now;
 model.CreatedBy = _myService.Username;

但是,我必须将这两个属性添加到接口IEntity,但这些属性仅属于某些模型,例如Lookup2 没有这两个属性。

我能想到的唯一解决方案是将nullableDateCreatedCreatedBy 属性添加到我的所有模型类中,这样我就可以将这些属性添加到IEntity 接口并更新我的通用控制器中的这些字段。但是我认为这并不理想,因为我没有兴趣为 Lookup2 设置这些属性

我的问题:

  1. 是否可以在接口中具有条件属性或可选地继承单独的条件接口?

  2. 还是我的问题的另一种更简洁的解决方案?

【问题讨论】:

  • AttributeCollectionDictionary&lt;string, object&gt; -&gt; PropertyName, Property 怎么样?
  • 否则您可以使用abstract class 而不是interface
  • 为什么您的实体实现接口 IEntity。您似乎没有在任何地方使用它?删除它,一切都会正常工作
  • 他在这行做:public class GenericRepository&lt;TEntity&gt; : IGenericRepository&lt;TEntity&gt; where TEntity : class, IEntity
  • 我添加了 IEntity 来证明如果我想在通用控制器中引用它,这些属性需要存在于其中

标签: c# oop generics interface


【解决方案1】:

使用另一个接口:

public interface ITraceableEntity : IEntity
{
     string CreatedBy { get; set; }
     DateTime CreatedDate { get; set; }
}

然后在你想要的具体类上实现它:

public class Lookup1 : ITraceableEntity
{
     public int Id { get; set; }

     public string Lookup1Name { get; set; }

     public string CreatedBy { get; set; }

     public DateTime CreatedDate { get; set; }
}

在通用控制器上,您可以检查实例是否正在实现此接口,然后进行转换:

try
{
    if (ModelState.IsValid) { 
        if (model is ITraceableEntity)
        {
           ((ITraceableEntity)model).CreatedBy = _myService.Username;  // <---
           ((ITraceableEntity)model).CreatedDate = DateTime.Now;       // <---
        }
        _repository.Update(model);
        await _repository.Save();
    }
}
catch (Exception)
{
    ModelState.AddModelError(string.Empty, "Unable to save changes.");
}
return View(model);

【讨论】:

  • 谢谢。您的代码似乎可以在控制器不必实现 ITraceableEntity 接口的情况下工作,所以我不需要将它添加到行 where TModel : class,IEntity
猜你喜欢
  • 2010-11-23
  • 2021-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多