【发布时间】:2011-03-24 08:12:25
【问题描述】:
首先,我想指出,我已经有了一个可行的解决方案,但我正在尝试看看是否有办法让代码更简洁、更简洁。
这是我的情况。我实际上已经简化了情况并创建了一个假示例以使插图清晰。我只是要展示一个具体的例子来展示我已经完成的工作,并且它是有效的。
假设我们有这些类:
public abstract class Shape{ //...elided... }
public class Square : Shape { //...elided... }
public class Circle : Shape { //...elided... }
假设有某种类可以像这样对它们做一些事情:
public class ShapeThingy
{
public static void MakeSquaresDance(List<Squares> squares){ //...elided... }
public static void RollCircles(List<Circles> circles){ //...elided... }
}
现在假设我想测试 ShapeThingy 类。假设对于某些测试,我想用 MockSquares 和 MockCircles 代替 Squares 和 Circles 到列表中。此外,假设设置 MockCircles 和 MockSquares 非常相似,因此我想要一种方法来创建模拟形状列表,并告诉该方法我需要的形状类型。以下是我的实现方式:
public class Tests
{
[Test]
public void TestDancingSquares()
{
List<Squares> mockSquares = GetMockShapes<Square, MockSquare>();
ShapeThingy.MakeSquaresDance(mockSquares);
Assert.Something();
}
[Test]
public void TestRollingCircles()
{
List<Circles> mockCircles = GetMockShapes<Circle, MockCircle>();
ShapeThingy.RollCircles(mockCircles );
Assert.Something();
}
private List<TBase> GetMockShapes<TBase, TMock>()
where TBase : Shape
where TMock : TBase, new()
{
List<TBase> mockShapes = new List<TBase>();
for (int i = 0; i < 5; i++)
{
mockShapes.Add(MockShapeFactory.CreateMockShape<TMock>());
}
}
}
public class MockSquare : Square { //...elided... }
public class MockCircle : Circle { //...elided... }
public class MockShapeFactory
{
public static T CreateMockShape<T>()
where T : Shape, new()
{
T mockShape = new T();
//do some kind of set up
return mockShape;
}
}
现在这工作正常。我遇到的问题是您已经向 GetMockShapes() 指定了所需的列表输出类型和您实际希望列表包含的模拟类型。实际上,我已经知道如果我向 GetMockShapes() 请求 List
我想做的是这样的:
private List<TBase> GetMockShapes<TBase>()
where TBase : Shape
{
List<TBase> mockShapes = new List<TBase>();
Type mockType = getAppropriateMockType<TBase>();
for (int i = 0; i < 5; i++)
{
//compiler error: typeof(mockType) doesn't work here
mockShapes.Add(MockShapeFactory.CreateMockShape<typeof(mockType)>());
}
}
private Type getAppropriateMockType<TBase>()
{
if(typeof(TBase).Equals(typeof(Square)))
{
return typeof(MockSquare);
}
if(typeof(TBase).Equals(typeof(Circle)))
{
return typeof(MockCircle);
}
//else
throw new ArgumentException(typeof(TBase).ToString() + " cannot be converted to a mock shape type.");
}
//add then a test would look like this
//(one less word, one less chance to screw up)
[Test]
public void TestDancingSquares()
{
List<Squares> mockSquares = GetMockShapes<Square>();
ShapeThingy.MakeSquaresDance(mockSquares);
Assert.Something();
}
问题是该版本无法编译,我想不出办法。也许我想做的事情是不可能的。
此时您可能会想,“如果他只使用 IEnumerable
无论如何,我想,我想要做的只是让自己免于在每次调用 GetMockShapes() 时输入一个额外的单词,所以这并不是什么大不了的事,我不知道,也许是很好,这两种类型都被指定了,这样一目了然。我只是觉得如果我能找到一些方法来做到这一点会很酷,而且我也会学到一些新东西。我主要想知道这是否可以满足我的好奇心。我不认为它在代码质量方面真的那么重要。
【问题讨论】:
-
好吧,在你的例子中它不会编译,因为
getAppropriateMockType没有被指定为通用的。将其指定为具有与第一种方法相同的约束的泛型,它会起作用吗? -
啊,谢谢。这修复了两个编译器错误之一,但还有另一个。我更正了该代码,还添加了注释以显示仍然导致问题的部分。
标签: c# generics c#-4.0 covariance