簡體   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