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