【问题标题】:Create an IEnumerable<SelectListItem> collection off a given type T in a generic class从泛型类中的给定类型 T 创建一个 IEnumerable<SelectListItem> 集合
【发布时间】:2015-04-02 11:47:39
【问题描述】:

我想添加一个方法,该方法将为我的项目中的实体创建一个 IEnumerable。所有实体都将呈现一个用于捕获/编辑的下拉列表,因此在我看来,将其添加到我的通用存储库方法中是有意义的。

我不太确定这是否可行,或者如何最好地解决这个问题,因为我使用的是泛型类,希望下面的代码能说明我的想法:

public interface ISpaceRepository<T> 
    where T : class
{
    SpaceResult<T> GetAll();
    SpaceResult<T> FindBy(Expression<Func<T, bool>> predicate);
    SpaceResult<T> Add(T entity);
    SpaceResult<T> Delete(T entity);
    SpaceResult<T> Edit(T entity);
    SpaceResult<T> FindById(int id);
    SpaceResult<T> SelectList();
}

非常基本的接口定义。这在我的 SpaceRespository 类中实现:

public class SpaceRepository<T>
    : ISpaceRepository<T> where T : class
{
    // content omitted for ease of reading
}

在我的存储库中,我想为 T 类型创建一个用于构建 IEnumerable 集合的方法。这里的问题是,默认情况下,T 不公开任何属性,所以我无法获得 T .Name 和 T.Id,所以我正在使用谓词来完成工作:

    public SpaceResult<T> SelectList(Expression<Func<T, bool>> predicate)
    {
        SpaceResult<T> result = new SpaceResult<T>();

        try
        {
            result.SelectList = this.GetAll().Select(predicate);
        }
        catch (System.Exception ex)
        {
            result.IsError = true;
            result.Message = ex.Message;
            result.InnerException = ex.InnerException.Message;
        }

        return result;
    }

这种方法有效,但每次构建选择项集合以绑定到 Razor (MVC) 中的下拉列表时,我都必须定义谓词。

有没有更简单的方法?反射成本太高。没有特别的理由不在视图模型级别这样做,我只是在学习时玩弄一些想法:$。

更新

这个想法是公开一个通用方法,该方法将为 T 的给定数据库实体在存储库模式中创建 SelectListItem 元素的集合,而无需我或其他开发人员为数据库中的每个表复制代码。

更新 1

一个例子:

ISpaceRepository<Building> _repo = new SpaceRepository<Building>();


SpaceResult<Building> result = this._repo.SelectList((x => new SelectListItem { 
  x.Id, 
  x.Description }));

更新 2

建筑是这样的:

[Table("buildings")]
public class Building
{
    [Column("id")]
    [Key]
    public int Id {get;set;}

    [Column("description")]
    public string Description {get;set;}
}

所以我想如果我在选择列表中我需要的列中添加一个自定义属性,我就可以使用反射,但这对于我所追求的解决方案来说听起来很昂贵。

[Table("buildings")]
public class Building
{
    [Column("id")]
    [Key]
    [SelectListItem]
    public int Id {get;set;}

    [Column("description")]
    [SelectListItem]
    public string Description {get;set;}
}

【问题讨论】:

  • "这在我的 SpaceRespository 类中被继承:" - nitpick:由于ISpaceRepository&lt;T&gt; 是一个接口,它在您的SpaceRepository 类中实现
  • 你能展示一个典型的predicate函数吗? T 的不同类型是否没有共同的祖先,可以提供所有可能类型 T 共有的任何属性?
  • 不是真的,我在设计这个时并没有考虑到选择列表,它是后来出现的。我会做类似 (x => new SelectListItem { x.Id, x.Description }) 的事情,因为并非所有表都有描述作为文本值,它要么是描述,要么是名称,要么是标题(糟糕的数据库设计,第 3 方)
  • 嗯,这不是一个predicate 函数,而是一些其他特定于类型的函数,它提供了有关项目的一些信息——您可能想要传递给SelectList,因此您可以使用它但是,在方法中返回值。
  • 我还在学习这些东西,主要来自 UI 开发 HTML / JavaScript,所以谢谢你纠正我:)。我正在使用返回,只是认为可能有一种更简单的方法:$

标签: c# generics selectlistitem


【解决方案1】:

怎么样:

interface IEntity {
    public int Id { get; }
    public string Name { get; }
}

[Table("buildings")]
public class Building : IEntity
{
    [Column("id")]
    [Key]
    public int Id {get;set;}

    [Column("description")]
    public string Description {get;set;}

    [NotMapped]
    public string Name { get { return this.Description; } }
}

[Table("cars")]
public class Car : IEntity
{
    [Column("id")]
    [Key]
    public int Id {get;set;}

    [Column("title")]
    public string Title {get;set;}

    [NotMapped]
    public string Name { get { return this.Title; } }
}

然后编写一个适用于实现此接口的元素的方法而不是通用方法就足够了吗?

方法:

public SpaceResult<IEntity> SelectList() 
{
    SpaceResult<IEntity> result = new SpaceResult<IEntity>();

    try
    {
        result.SelectList = this.GetAll().Select(x => new SelectListItem { x.Id, x.Name });
    }
    catch (System.Exception ex)
    {
        result.IsError = true;
        result.Message = ex.Message;
        result.InnerException = ex.InnerException.Message;
    }

    return result;
}

用法:

ISpaceRepository<Building> _repo = new SpaceRepository<Building>();
SpaceResult<IEntity> result = this._repo.SelectList();

ISpaceRepository<Car> _repo = new SpaceRepository<Car>();
SpaceResult<IEntity> result = this._repo.SelectList();

只要你所有的实体类都实现了通用接口,就可以应用相同的方法。

【讨论】:

  • 可以工作,是的,但我想在我的存储库模式中创建一个通用方法来满足我数据库中的所有表,允许它们公开一个 IEnumerable 而无需重新创建此方法对于视图模型中的每个表。如果这有意义?
  • 确实有道理。但我的建议并没有太大的不同。我将很快详细说明我的答案。
  • 我在玩你指出的想法。基本上,T 实现了 IEntity,它只有两个属性,所以这些属性将用于构建项目...
  • 正确。此外,通过这种方式,定义如何生成 SelectListItem 的责任部分地被实体化了。
  • 这几乎指导了我正确的方向,谢谢@tafa。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-23
  • 2021-01-04
  • 1970-01-01
  • 1970-01-01
  • 2016-08-24
相关资源
最近更新 更多