如何强制泛型类使用带有参数的T构造函数?

时间:2012-01-03 09:10:29

标签: c# generics

我有一个像这样的Generic类:

public class Mapper<TEntity, TDataAccess>
    where TEntity : Common.IEntity
    where TDataAccess : DataAccess, new()
{
    public TDataAccess DataAccess { get; set; } 
    public Mapper()
    {
        DataAccess = new TDataAccess();
    }
    /*
     * ...
     * */
}

和数据访问是这样的:

public class DataAccess
{
    public DataAccess()
    {}

    public DataAccess(string tranName)
    {}

    // CRUD functionality and other data access staff
}

和继承的类表单DataAccess

public class UserDataAccess:DataAccess
{
    public UserDataAccess():base(string.Empty)
    {
    }
    public UserDataAccess(string tranName):base(tranName)
    {
        // Something to do with user
    }
}
来自Mapper的

和最后UserMapper

public class UserMapper : Mapper<User,UserDataAccess>
{
    // Mapping entity properties with datarows columns
}

现在想象一下,我需要tranNameTDataAccess中的UserMapper发送DataAccess。如何在不改变DataAccess类的情况下做到这一点?我无法访问UserDataAccess的源代码,并且Generics也没有实现类型不同的构造函数重载。 我知道我可以在User上有一个属性并在需要时填写它,但我不能因为线程安全问题而填写。

{{1}}类是一个普通实体 - 它只有属性。

2 个答案:

答案 0 :(得分:3)

作为一种情况,您可以通过指定构造函数参数来使用Activator.CreateInstance()方法的重载:

var dataAccess = Activator.CreateInstance(
                            typeof(TDataAccess), 
                            new object[] { tranName });

MSDN

public static Object CreateInstance(
    Type type,
    params Object[] args
)
  

使用构造函数创建指定类型的实例   最符合指定的参数。

答案 1 :(得分:2)

泛型不支持这一点。选项:

  • 有一个protected virtual TDataAccess CreateDataAccess()方法,默认情况下使用new TDataAccess(),但UserMapper可以覆盖该方法以任意方式创建对象;致电CreateDataAccess()而非new TDataAccess()
  • 作为代理传递工厂方法,即Func<TDataAccess> - 因此调用者可以提供() => new DataAccess("foo"),并使用该代替new TDataAccess()
  • 使用基于反射的代码创建TDataAccess - Activator.CreateInstance(支持参数)或涉及元编程的内容(ExpressionILGenerator等)