繁体   English   中英

C# - 在构造函数中键入参数 - 没有泛型

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM