抱歉,这是一个很长的描述!
我有一个代表给定值的通用类。
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
,但是如果我想使用自定义类,则此操作将失败。例如对于type 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
方法的接口,因此不会通过接口调用方法。Moq创建的Mock对象创建了的显式实现ToString
,并且不会覆盖从继承的System.Object
,因此您将获得错误/意外的结果。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句