Generic Identification Card in C #. Do not want a public constructor

I am trying to implement an ID card using generics. I have an abstract class, Entity, and a derivation constraint on my map for Entity. Since my map must be able to create objects, my map also has a constructor constraint.

However, in order for the map to be useful, Entity subclasses should not be created from client code, which means that I need an internal constructor and no public constructors. However, this conflicts with the constructor restriction.

Is there something I am missing? Is there a way to refactor to get the desired result?

The following code compiles as is, but ideally, the constructors of the Entity subclass will be internal:

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>();
}
+5
2

, , 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> ID. , , Entity.

( Get , .)

+9

Jon, :

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));
}
+2

All Articles