代码之家  ›  专栏  ›  技术社区  ›  BeemerGuy

其中()在抽象级别返回新的自身

  •  3
  • BeemerGuy  · 技术社区  · 15 年前

    我有这个代码,我想保持它的优雅。
    我在继承问题上陷入困境,如果我这样做的话,我将不得不把代码弄乱。
    帮我保持优雅。我不介意在层次结构的上下任何地方进行更改;随时可以更改核心。

    我有这些抽象类(我省略了不相关的实现以缩短问题内容)。

    public abstract class Entity : IComparable 
    { 
        protected int _ID;
        public abstract int ID { get; } 
    }    
    public abstract class SortedEntities<T> : IEnumerable<T> where T : Entity 
    { 
        Dictionary<int,T> _Entities;
    }
    

    显然,继承的例子如下:

    public class Contact : Entity { }
    public class Contacts : SortedEntities<Contact> { }
    

    我还有不止 Contact Contacts 继承自 Entity SortedEntities 所有的行为都是一样的。

    在我的应用程序中的某个时刻,我想根据和ID列表选择实体。
    我想要的示例代码是:

    Contacts LoadedContacts = new Contacts();  // load and fill somewhere else
    // !!!NOT IMPLEMENTED YET!!!
    Contacts SelectedContacts = LoadedContacts.GetFromIDList("1,4,7");
    

    当它返回一个新的 联络 填充这些内容的对象 接触 提供的ID的对象。
    因此,允许所有继承自 分类实体 我想把这个想象中的代码添加到摘要中:

    public abstract class SortedEntities<T> : IEnumerable<T> where T : Entity 
    {
        // !!!NOT REAL CODE YET!!!
        public abstract this<T> GetFromIDList(string IDCSV)
        {
            List<string> idlist = IDCSV.Split(',').ToList<string>();
            return this.Where(entity => idlist.Contains(entity.ID.ToString()));
        }
    }
    

    但显然 this<T> 是不允许的。
    我要告诉编译器的是让这个方法的返回类型成为继承类的返回类型。
    这样,如果有人打电话 LoadedContacts.GetFromIDList("1,4,7") 它会回来 联络 不必从 SortedEntities<T> 如果我将其设置为返回类型,这也要求我重写每个继承类中的方法以隐藏抽象方法。

    我忘了我已经知道的东西了吗?
    或者这是完全不可能的,我必须重写并隐藏所有继承类的层次结构中的方法?

    1 回复  |  直到 15 年前
        1
  •  1
  •   dtb    15 年前

    常见的解决方案是添加另一个引用“当前”类型的泛型类型参数(如 this 指“当前”对象):

    public abstract class Entity : IComparable
    {
        protected int _ID;
        public abstract int ID { get; }
    }
    
    public abstract class SortedEntities<TEntities, TEntity> : IEnumerable<TEntity>
        where TEntities : SortedEntities<TEntities, TEntity>, new()
        where TEntity : Entity
    {
        Dictionary<int, TEntity> _Entities;
    
        public TEntities GetFromIDList(string IDCSV)
        {
            List<string> ids = IDCSV.Split(',').ToList<string>();
            return new TEntities
            {
                _Entities = this.Where(entity => ids.Contains(entity.ID.ToString()))
                                .ToDictionary(e => e.ID)
            };
        }
    }
    

    用途:

    public class Contact : Entity
    {
    }
    
    public class Contacts : SortedEntities<Contacts, Contact>
    {
    }
    

    注意如何 TEntities 仅限于 SortedEntities<TEntities, TEntity> . 这并不意味着 张力 只能引用当前类,但只要您遵循“让类”的模式 X 继承自 SortedEntities<X, Y> ,应该可以。

    这个 new() 约束是必需的,因此您可以实例化“当前”类的新实例。

    埃里克·利珀特在别处表示他不喜欢这种模式。自担风险!