![](/img/trans.png)
[英]C# generics problem - newing up the generic type with parameters in the constructor
[英]C# - Type Parameters in Constructor - No Generics
我有一个课程,我正在尝试进行单元测试。 该类是WCF服务类。 (将它作为泛型类不是我的目标。)
我有一个数据访问层(DAL)类型(称为UserDAL),它在许多方法中实例化。 为了使这些方法得到测试,我需要模拟这个局部变量。 (UserDAL的每个实例都有特定于方法的值,因此将其更改为类级变量会导致代码混乱,所以我宁愿不这样做。)
我认为很好的是重载构造函数并传入一个类型以在本地方法中使用。 空param构造函数仍然会创建一个普通的UserDAL,但是重载的那个将有一个实现IUserDAL的mock类型。
我不确定语法是否要传递一个类型。 请注意,我不是要传递变量,而是传递类型。
例:
public class MyWCFClass: IMyWCFClass
{
private TypeParam _myUserDALType;
public MyWCFClass()
{
_myUserDALType = UserDAL;
}
public MyWCFClass(TypeParam myUserDALType)
{
_myUserDALType = myUserDALType;
}
//methods to use it
public MyMethod()
{
IUserDAL userDAL = new _myUserDALType();
//Call method in IUserDAL
userDAL.CreateUser();
}
// Several similar methods that all need a different UserDAL go here
.....
}
所以,我不知道TypeParam是什么类型的(我做了那个)或者这种想法是否可能。
如果你有一个非常规的非泛型解决方案。
您真正需要的是依赖注入,但您可以通过传入Type参数然后使用Activator.CreateInstance(Type)在需要时创建对象来完成此操作。
至于做真正的DI(这将使这个测试更容易),我知道Spring.Net工作得很好。
使用Type,并使用Activator.CreateInstance实例化它:
private Type _myUserDALType;
IUserDAL userDAL = Activator.CreateInstance(_myUserDALType) as IUserDAL;
您的意思是Type
,使用Activator.CreateInstance
创建实例:
public class MyWCFClass: IMyWCFClass
{
private Type _myUserDALType;
public MyWCFClass()
{
_myUserDALType = typeof(UserDAL);
}
public MyWCFClass(Type myUserDALType)
{
_myUserDALType = myUserDALType;
}
//methods to use it
public void MyMethod()
{
IUserDAL userDAL = (IUserDAL) Activator.CreateInstance(_myUserDALType );
//Call method in IUserDAL
userDAL.CreateUser();
}
}
你真正的问题不在于泛型或缺乏。 你真正的问题是MyWFCClass
正在调用new
和方法。 根据Misko Hevery ,通过将调用new
的类与实现逻辑的类分开,可以获得最佳的可测试性。 不要让MyWFCClass
知道你想要实现的类型和使用反射,只需将IUserDal
对象传递给构造函数,允许测试工具在需要时传入模拟对象。
如果由于某种原因,你不能这样做,你不能使用泛型,那么你必须自己做。 将Type
对象传递给MyWFCClass
构造函数,然后使用反射来查找和调用所需的构造函数。
如果要传入类型,可以使用Type对象:
public class A
{
public A(Type classType)
{
object myObject = Activator.CreateInstance(...classType...);
}
}
public class B
{
...
}
public class C
{
public static void main(string[] args)
{
A a = new A(typeof(B));
}
}
如果IUserDAL
定义了WCF服务完成其工作所需的接口,为什么不将它的实例作为构造函数参数? 既然WCF需要默认构造函数,为什么不让默认构造函数使用默认实现调用参数化构造函数?
public class MyWCFClass : IMyWCFClass
{
private readonly IUserDAL _userDAL;
public MyWCFClass()
: this(new DefaultUserDAL())
{
}
public MyWCFClass(IUserDAL userDAL)
{
_userDAL = userDAL;
}
}
如果您正在使用依赖项注入容器,则可以将其公开为单例并使用该单例来满足参数化构造函数:
public MyWCFClass()
this(Container.Instance.Resolve<IUserDAL>())
{
}
使用这种方法,您的WCF类具有完成其工作所需的一切,但它仍然是可单元测试的。 而且,它不负责创建依赖项,这是一件好事。
更简单,并且与其他具有此问题的应用程序更加一致,就是在UserDal上提取接口,然后您会有更多类似的东西:
public MyWCFClass() : this(new UserDAL())
{
}
public MyWCFClass(IUserDal userDAL)
{
_myUserDAL = myUserDAL;
}
这种依赖注入框架比你提出的方法更容易使用,尽管这肯定是次要问题
(编辑以澄清基于其他评论的替代解决方案)
如果您的DAL在使用后基本上没有价值,因为它是变异的,请使用IUserDalFactory构造函数,使用一个方法Create()
。
在C#中有一种名为“Type”的类型。 有了它,您可以创建一个参数并传入任何有效的类型。
private void MyMethod(Type myType)
{
//Do something
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.