簡體   English   中英

使用泛型類型投射模擬

[英]Casting mock using generic type

抱歉,這是一個很長的描述!

我有一個代表給定值的通用類。

public class ValueClass<T>
{
    public object Value { get { return this._value; } }
    protected T _value;

    public ValueClass(T value)
    {
        this._value = value;
    }

    public string Print()
    {
        return ((T)this.Value).ToString();
    }
}

可以如下所示執行:

[TestCase(1, "1")]
[TestCase(2, "2")]
public void Works(int value, string expected)
{
    ValueClass<int> uut = new ValueClass<int>(value);

    string ret = uut.Print();

    Assert.AreEqual(expected, ret);
}

這對於int類的類型工作正常,但是如果我想使用自定義類,則此操作將失敗。 例如對於類型ICustomType ,應調用ToString方法。

public interface ICustomType
{
    string ToString();
}

因此,以下測試失敗了,在其中ICustomType

[TestCase("1")]
[TestCase("2")]
public void Fails(string expected)
{
    Mock<ICustomType> customTypeStub = new Mock<ICustomType>();
    customTypeStub.Setup(x => x.ToString()).Returns(expected);

    ValueClass<ICustomType> uut = new ValueClass<ICustomType>(customTypeStub.Object);

    string ret = uut.Print();

    Assert.AreEqual(expected, ret);
}

(下面添加了其他診斷行-轉換為特定類型的作品,但不轉換為T型)

public class ValueClass<T>
{
    public object Value { get { return this._value; } }
    protected T _value;

    public ValueClass(T value)
    {
        this._value = value;
    }

    public string Print()
    {
        Console.WriteLine("this.Value.ToString() : " + this.Value.ToString());
        Console.WriteLine("((ICustomType)this.Value).ToString() : " + ((ICustomType)this.Value).ToString());
        Console.WriteLine("((T)this.Value).ToString() : " + ((T)this.Value).ToString());
        Console.WriteLine("typeof(T) : " + typeof(T));
        Console.WriteLine("(typeof(T) == typeof(ICustomType)) : " + (typeof(T) == typeof(ICustomType)));

        return ((T)this.Value).ToString();
    }
}

以下診斷信息:

***** tests.Types.Fails("1")
this.Value.ToString() : Castle.Proxies.ICustomTypeProxy
((T)this.Value).ToString() : Castle.Proxies.ICustomTypeProxy
typeof(T) : Types.ICustomType
(typeof(T) == typeof(ICustomType)) : True
***** tests.Types.Fails("2")
this.Value.ToString() : Castle.Proxies.ICustomTypeProxy
((T)this.Value).ToString() : Castle.Proxies.ICustomTypeProxy
typeof(T) : Types.ICustomType
(typeof(T) == typeof(ICustomType)) : True

據我所知,Moq正確地模擬了ToString方法。 手動強制轉換為固定類型時,此方法效果很好。 但是,當依靠通用類型T定義轉換時,此操作將失敗。

請注意,我必須將Value保留為類型object而不是類型T是ValueClass實現了非通用接口-值必須可訪問,但不能在接口級別定義類型。 誰能解釋這種行為?

這里的問題是,編譯器不知道您打算為它提供一個接口,該接口指示編譯器使用每個對象都不同的 ToString方法。

編譯器唯一了解T某種類型 編譯器將在編譯時使用已知的方法對該方法進行編譯,即使您稍后為其提供一個接口,該接口實際上告訴它使用其他ToString方法,它也不會使用它,因為它已經編譯了該方法。 所有類型的方法,並且該編譯使用System.Object提供的一種。

因此,您無法以這種方式進行操作。

可以指示ValueClass僅支持實現您的接口的T類型,但是我懷疑那不是您想要的。

這是Print方法的編譯方式:

ValueClass`1.Print:
IL_0000:  ldarg.0     
IL_0001:  call        15 00 00 0A 
IL_0006:  unbox.any   05 00 00 1B 
IL_000B:  stloc.0     // CS$0$0000
IL_000C:  ldloca.s    00 // CS$0$0000
IL_000E:  constrained. 05 00 00 1B 
IL_0014:  callvirt    System.Object.ToString
IL_0019:  ret         

如您所見,它被編譯為直接調用System.Object.ToString ,顯然您可以覆蓋提供給T的實際類型,但是編譯器無法理解您在某些情況下打算為其提供接口,它自己的ToString方法,因此不會通過interface調用該方法。 Moq創建的Mock對象將創建ToString的顯式實現,並且不會覆蓋從System.Object繼承的對象,因此您將獲得錯誤/意外的結果。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM