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

C#中的通用标识映射。不想要公共构造函数

  •  5
  • Lobstrosity  · 技术社区  · 16 年前

    我正在尝试实现一个 identity map 使用泛型。我在Entity的映射上有一个抽象类Entity和一个派生约束。由于我的映射需要能够实例化实体,因此我的映射还具有构造函数约束。

    然而,为了使映射有用,实体子类不应该能够从客户端代码中实例化,这意味着我想要一个内部构造函数,而不是公共构造函数。不过,这与构造函数约束冲突。

    我错过了什么吗?是否有某种重构方法来获得所需的结果?

    public abstract class Entity
    {
        public int Id { get; protected internal set; }
    }
    
    public sealed class Widget : Entity
    {
        // Client code should not be allowed to instantiate entities.
        // But the constraints on EntityMap require that entities have
        // a public constructor.
        public Widget() { }
    }
    
    public sealed class Gadget : Entity
    {
        public Gadget() { }
    }
    
    // The new() constraint is required so that Get() can instantiate Ts.
    public class EntityMap<T> where T : Entity, new()
    {
        private Dictionary<int, T> _entities = new Dictionary<int, T>();
        private object _getLock = new object();
    
        public T Get(int id)
        {
            lock (_getLock)
            {
                if (!_entities.ContainsKey(id))
                    _entities.Add(id, new T() { Id = id });
            }
    
            return _entities[id];
        }
    
        // Client code should not be allowed to instantiate maps.
        internal EntityMap() { }
    }
    
    // Ideally, the client would only be able to obtain Entity
    // references through EntityMaps, which are only accessible
    // through the ApplicationMap.
    public static class ApplicationMap
    {
        public static EntityMap<Widget> Widgets = new EntityMap<Widget>();
        public static EntityMap<Gadget> Gadgets = new EntityMap<Gadget>();
    }
    
    2 回复  |  直到 16 年前
        1
  •  9
  •   Jon Skeet    16 年前

    Func<T>

    public class EntityMap<T> where T : Entity
    {
        private readonly Dictionary<int, T> _entities = new Dictionary<int, T>();
        private readonly object _getLock = new object();
        private readonly Func<T> _entityGenerator;
    
        public T Get(int id)
        {
            lock (_getLock)
            {
                T ret;
                if (!_entities.TryGetValue(id, ret))
                {
                    ret = entityGenerator();
                    newEntity[id] = ret;
                    ret.Id = id;
                }
    
                return ret;
            }
        }
    
        internal EntityMap(Func<T> entityGenerator)
        {
            _entityGenerator = entityGenerator;
        }
    }
    

    然后用以下代码初始化:

    EntityMap<Widget> widgetMap = new EntityMap(() => new Widget());
    

    Func<int, T> Entity

    Get

        2
  •  2
  •   Lobstrosity    16 年前

    public abstract class Entity
    {
        private readonly int _id;
    
        public int Id
        {
            get { return _id; }
        }
    
        internal Entity(int id)
        {
            _id = id;
        }
    }
    
    public sealed class Widget : Entity
    {
        internal Widget(int id) : base(id) { }
    }
    
    public sealed class Gadget : Entity
    {
        internal Gadget(int id) : base(id) { }
    }
    
    public class EntityMap<T> where T : Entity
    {
        private readonly Dictionary<int, T> _entities = new Dictionary<int, T>();
        private readonly object _getLock = new object();
        private readonly Func<int, T> _entityGenerator;
    
        public T Get(int id)
        {
            lock (_getLock)
            {
                T entity;
    
                if (!_entities.TryGetValue(id, out entity))
                    _entities[id] = entity = _entityGenerator(id);
    
                return entity;
            }
        }
    
        internal EntityMap(Func<int, T> entityGenerator)
        {
            _entityGenerator = entityGenerator;
        }
    }
    
    public static class ApplicationMap
    {
        public static readonly EntityMap<Widget> Widgets = new EntityMap<Widget>(id => new Widget(id));
        public static readonly EntityMap<Gadget> Gadgets = new EntityMap<Gadget>(id => new Gadget(id));
    }
    
    推荐文章