如何从类型参数创建类实例?

时间:2014-02-23 21:31:05

标签: c# generics

我想创建一个使用字典的小类工厂,但是我不得不分开一个实例的创建并从字典中获取一个实例。

Instantiate看起来像这样:

public void CreateInstance<T>(string id) where T : class, new()
{
    lock (_syncroot)
    {
        _internal_dict.Add(id, new T());
    }
}

它运行良好,但问题是,如果我想实例化一个必须参数化构造函数的类,我该怎么办?

是否有任何解决方案或建筑最佳实践?

3 个答案:

答案 0 :(得分:0)

T除了class之外没有任何约束,唯一真正的选择是通过Activator类使用Refelction。

//Still used for the no parameter constructor checking.
public void CreateInstance<T>(string id) where T : class, new()
{
    lock (_syncroot)
    {
        _internal_dict.Add(id, new T());
    }
}

public void CreateInstance<T>(string id, params object[] args) where T : class
{
    lock (_syncroot)
    {
        _internal_dict.Add(id, Activator.CreateInstance(typeof(T), args));
    }
}

请注意,这会删除执行编译时检查的能力,即您为<T>选择的类具有可以调用的正确公共构造函数,如果找不到构造函数,则可能在运行时抛出异常

答案 1 :(得分:0)

不可能约束类型参数,因此它需要一个类具有参数化构造函数。

您可以做的最好的事情是要求类实现具有工厂方法的接口,然后从泛型方法内部调用工厂方法。

来自“Essential C#”,第4版:

public class EntityBase<TKey>
{
    public EntityBase(TKey key)
    {
        Key = key;
    }

    public TKey Key
    {
        get {return _key;}
        set {_key = value;}
    }
    private TKey _key;
}

public class EntityDictionary<TKey, TValue, TFactory> :
    Dictionary<TKey, TValue>
    where TKey : IComparable<T>, IFormattable
    where TValue : EntityBase<TKey>
    where TFactory : IEntityFactory<TKey, TValue>, new()
{
    public TValue New(TKey key)
    {
        TValue newEntity = new TFactory().CreateNew(key);
        Add(newEntity.Key, newEntity);
        return newEntity;
    }
}

public interface IEntityFactory<TKey, TValue>
{
    TValue CreateNew(TKey key);
}

EntityDictionary类需要创建EntityBase的实例,但这需要参数化构造函数。要解决这个问题,请创建一个实现IEntityFactory<TKey, TValue>的类,并且该类具有默认构造函数。该类将知道如何调用EntityBase构造函数。

答案 2 :(得分:0)

在我看来,您正在尝试创建一个对象存储库,而不是工厂。对于存储库,在将对象添加到存储库之前更容易实例化对象。

repository.Add(key, new SomeType(arg1, arg2));

如果要添加到存储库的所有对象都派生自公共类型或实现某个公共接口,则只需使用键入的Dictionary<TKey, TValue>。例如:

private Dictionary<string, IGameObject> _gameObjects = 
                                                new Dictionary<string, IGameObject>();

_gameObjects.Add("car", new Car(maxSpeed));
_gameObjects.Add("monster", new Monster());

并使用以下方法检索它:

IGameObject obj = _gameObjects(key);

如果您打算存储完全不相关的类型,请使用由类型和可能的标识符组成的复合键。

public class Repository
{
    private class RepositoryKey
    {
        public RepositoryKey(Type type, string key)
        {
            this.Type = type;
            this.Key = key;
        }

        public Type Type { get; private set; }
        public string Key { get; private set; }

        //TODO: override Equals and GetHashCode.
    }

    private Dictionary<RepositoryKey, object> _dict =
                                              new Dictionary<RepositoryKey, object>();

    public void Add<T>(string key, T obj)
    {
        _dict.Add(new RepositoryKey(typeof(T), key), obj);
    }

    public Get<T>(string key)
    {
        return (T)_dict[new RepositoryKey(typeof(T), key)];
    }
}

这只是一个简单的实现,没有错误处理。

var rep = new Repository();
rep.Add("slow", new Car(30));
rep.Add("fast", new Car(180));
rep.Add("left", new Monster(x1, y1));
rep.Add("right", new Monster(x2, y2));

...

Car fastCar = rep.Get<Car>("fast");
Monster leftMonster = rep.Get<Monster>("left");