首先,我想指出,我已經有一個工作解決方案,但我正在嘗試查看是否有方法使代碼更清晰並且不那麼繁瑣。推斷基於另一個指定泛型類型的泛型類型並使用它
這是我的情況。我實際上已經簡化了情況,並創建了一個假的例子來說明清楚。我只是要展示一個具體的例子,展示我已經完成了什麼,它的工作原理。
假設我們有這些類:
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