使用泛型类型投射模拟

标记

抱歉,这是一个很长的描述!

我有一个代表给定值的通用类。

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] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

Mockito ClassCastException-无法投射模拟

来自分类Dev

投射泛型类型的地图列表

来自分类Dev

投射泛型集合项类型

来自分类Dev

PowerMock / Mockito投射模拟对象不起作用

来自分类Dev

泛型-动态使用类型

来自分类Dev

Java的泛型类型使用

来自分类Dev

泛型-使用父类在泛型中指定类型

来自分类Dev

使用泛型向地图添加泛型类型的对象

来自分类Dev

Typescript:泛型,使用泛型扩展类型

来自分类Dev

如何使用泛型返回泛型类的类类型?

来自分类Dev

具有隐式泛型类型的Scala模拟函数

来自分类Dev

如何模拟 IServiceProvider 并仍然允许泛型类型的 CreateInstance?

来自分类Dev

如何模拟接受类类型的泛型方法?

来自分类Dev

在泛型类中使用匿名类型

来自分类Dev

如何使用类型的辅助类泛型

来自分类Dev

使用泛型进行类型检查

来自分类Dev

使用泛型类型调用重载函数

来自分类Dev

使用类对象作为泛型类型

来自分类Dev

使用java classmate解决泛型类型

来自分类Dev

使用类实例作为泛型类型

来自分类Dev

使用泛型作为返回类型

来自分类Dev

如何使用泛型实现类型安全?

来自分类Dev

Java中的泛型类型使用

来自分类Dev

使用Shapeless的泛型类型转换

来自分类Dev

覆盖方法的问题(使用泛型类型)

来自分类Dev

使用泛型参数化属性类型

来自分类Dev

使用从类型枚举中选择的泛型

来自分类Dev

使用泛型的不兼容类型

来自分类Dev

使用Java Classmate解决泛型类型