代码之家  ›  专栏  ›  技术社区  ›  Sonny Boy

为基类型创建集合,方法将在所有继承的对象上工作?

  •  2
  • Sonny Boy  · 技术社区  · 15 年前

    我目前正在启动一个新项目,遇到了一些读块。我希望有人能帮助我,我会尽我所能描述这个问题。

    我有一个名为“EntityBase”的基本抽象类。从这个类中继承了大约100个类。EntityBase有许多方法,如Load()和Save(),这些方法对我继承的所有类都是通用的。它还具有两个构造函数,它们接受整数或IDataReader,用于从数据库加载对象。

    一切都很顺利。

    输入我的新基类,名为EntityCollectionBase,它扩展了列表<EntityBase>。我正在尝试为它编写一个加载函数,但我不确定如何继续。希望这段代码能更好地说明我的目标:

     public bool Load()
     {
         bool result = true;
    
         using (IDataReader reader = _dbManager.ExectureReaderSProc(this.LoadProcedure, new SqlParameter[] { new SqlParameter("@parentId", _parentID) }))
         {
             this.Add(new EntityBase(reader)); // WON'T WORK, EntityBase IS ABSTRACT
         }
    
         return result;
     }
    

    正如您所看到的,我需要加载函数以一种通用的方式来处理扩展EntityBase的任何事情,但是由于EntityBase是抽象的,所以我不能声明它。

    有什么想法吗?

    谢谢,
    桑尼

    5 回复  |  直到 15 年前
        1
  •  1
  •   Bryan Watts    15 年前

    每当您基于运行时数据创建多个可能类之一的实例时,工厂就是答案:

    public interface IEntityFactory
    {
        EntityBase CreateEntity(IDataReader reader);
    }
    

    您将修改加载类以接受一个:

    private readonly IEntityFactory _entityFactory;
    
    public Loader(IEntityFactory entityFactory)
    {
        _entityFactory = entityFactory;
    }
    

    那你就用工厂里的 Load 方法:

    public void Load()
    {
        using(var reader = _dbManager.ExectureReaderSProc(this.LoadProcedure, new SqlParameter[] { new SqlParameter("@parentId", _parentID) }))
        {
            Add(_entityFactory.CreateEntity(reader));
        }
    }
    
        2
  •  1
  •   Lee    15 年前

    您需要使用反射来访问采用 IDataReader . 当前示例也只加载一个项,这可能不是加载集合时所需的:

    public class EntityCollectionBase<T> where T : EntityBase
    {
        public void Load()
        {
            var constructorInfo = typeof(T).GetConstructor(new[] { typeof(IDataReader) });
            using(IDataReader reader = ...)
            {
                while(reader.Read())
                {
                    T entity = (T)constructorInfo.Invoke(new object[] { reader });
                    this.Add(entity);
                }
            }
        }
    }
    

    我会考虑将此设置为静态,因为如果 偶像崇拜者 加载时引发异常:

    public static EntityCollectionBase<T> Load() { ... }
    
        3
  •  0
  •   Mark H    15 年前

    给你 EntityBase void SetReader(IDataReader) 方法,并确保所有实体都具有默认构造函数。

    public bool Load<T>() where T : EntityBase, new()
    {
        ...
        using (IDataReader reader = _dbManager.ExectureReaderSProc(
            this.LoadProcedure, new SqlParameter[] {new SqlParameter("@parentId", _parentID) })) {
            EntityBase entity = new T();
            entity.SetReader(reader);
            this.Add(entity);
        }
        ...
    }
    
        4
  •  0
  •   Anthony Pegram    15 年前

    我可能会选择一个与之相反的通用集合类 EntityBase ,然后可以按照以下方式实例化和添加对象。但是,此代码假定您有一个接受整数参数的构造函数。如果不这样做,这个代码将被正确地放大。

    class EntityCollectionBase<T> : List<T> where T : EntityBase
    {
        public void Load()
        {
            // example
            int someId = 14;
            T t = (T)Activator.CreateInstance(typeof(T), someId);
            this.Add(t);
        }
    }
    

    一种更安全的方法是进一步约束T,使其具有无参数的构造函数,并在基类中具有方法*,该方法将从整数或DataReader加载(*或在基中是抽象的,在派生中实现)。

    class EntityCollectionBase<T> : List<T> where T : EntityBase, new()
    {
        public void Load()
        {
            // example
            int someId = 14;
            T t = new T();
            t.Load(someId);
            this.Add(t);
        }
    }
    
        5
  •  0
  •   Felipe Pessoto    15 年前

    也许这行得通。但是我更喜欢工厂班

    public class EntityCollectionBase<T> : List<T> where T : EntityBase, new()
    {
        public EntityBase Load()
        {
            return new T().Create(10);
        }
    }
    
    public abstract class EntityBase
    {
        public abstract EntityBase Create(int a);
    }