C#中的通用身份映射.不想要公共构造函数

Lob*_*ity 5 c# generics design-patterns

我正在尝试使用泛型实现身份映射.我的实体地图上有一个抽象类,实体和派生约束.由于我的地图需要能够实例化实体,我的地图也有一个构造函数约束.

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

有什么我想念的吗?有没有办法重构这个以获得理想的结果?

下面的代码按原样编译,但理想情况下,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>();
}
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 9

不需要构造函数约束,而是将a传递Func<T>给map构造函数.这样构造函数可以是内部的,但地图仍然可以有效地调用它:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后用以下内容初始化它:

EntityMap<Widget> widgetMap = new EntityMap(() => new Widget());
Run Code Online (Sandbox Code Playgroud)

您可能会Func<int, T>改为使其成为代理,并使委托负责创建具有正确ID的实体.这样,您可以将您的ID设置为只读,将其作为Entity构造函数的参数.

(我冒昧地让你的Get方法更有效率,顺便说一下.)