首先,我想指出,我已经有一个工作解决方案,但我正在尝试查看是否有方法使代码更清晰并且不那么繁琐。推断基于另一个指定泛型类型的泛型类型并使用它
这是我的情况。我实际上已经简化了情况,并创建了一个假的例子来说明清楚。我只是要展示一个具体的例子,展示我已经完成了什么,它的工作原理。
假设我们有这些类:
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代替正方形和圆形的列表。另外,假设设置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()获得列表<Square>,那么它实际上应该被MockSquare填充。必须一遍又一遍地指定这两件事情是很麻烦的。
我想要做的是这样的:
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 <牛逼>而不是List <牛逼>,那么他就可以利用在C#4.0协方差的,他不会做任何的这个废话“,这是真的,但在我们真实的代码中,我们并没有使用List <T>,而是使用自定义具体类型,Something <T>(并且它不是IEnumerable样式集合),而且我不' t有能力改变Something <T>的使用,并且现在引入一个协变接口ISomething < out T >。不管怎么说,我想要做的所有事情,我想,只要我打电话给GetMockShapes(),就不用再输入一个额外的单词,所以它不是真的那么重要,我也不知道,也许,也许这两种类型都是明确的,以便看清楚是很好的。我只是想,如果我能找到某种方式来做到这一点,那将是一件很酷的事情,我也会学到一些新的东西。我主要想知道这是否能够满足我的好奇心。在代码质量方面,我认为这并不重要。
好吧,在你的例子中它不会编译,因为'getAppropriateMockType'没有被指定为通用的。将它指定为具有与第一个方法相同的约束的泛型,它会起作用吗? – 2011-03-24 08:30:51
啊,谢谢。这解决了两个编译器错误之一,但还有另一个。我纠正了这些代码,并且还添加了一条评论来显示仍然导致问题的部分。 – olanmills 2011-03-24 09:09:35
查看回答发贴数。 – 2011-03-24 10:00:57