2013-03-22 81 views
2

我有幾個類都繼承了相同的Shape類。當我創建一個新形狀時,我希望它具有隨機形狀。我認爲這樣做的方式是創建一個鏈接到所有構造函數的列表,並且當我需要創建一個新形狀時,我將從列表中獲取一個隨機構造函數,並使用它來構造我的形狀。我試圖創建休耕方式的名單,但我得到的錯誤:是否有可能在c#中創建一個將創建隨機對象的構造函數列表?

List<Action> constList = new List<Action>(); 
constList.Add(SShape()); 
constList.Add(OShape()); 
constList.Add(LShape()); 

Shape構造函數定義:

class Shape 
{ 
    public Shape(PlayGrid grid, Color color) 
    { 
     ... 
    } 
    ... 
} 

每個子形狀的構造函數的定義如下:

class IShape : Shape 
{ 
    public IShape(PlayGrid grid, Color color) : base(grid, color) 
    { 
    ... 
    } 
... 
} 

什麼是構造列表的正確方法,以及如何使用列表中的構造函數?

承包商還需要獲取在不同形狀之間變化的參數。

+1

在你的形狀基類中,有一個靜態函數GetRandomShape() – 2013-03-22 12:24:08

+1

你的形狀類是Action的子類嗎? – 2013-03-22 12:24:15

+0

@StealthRabbi,no。 – SIMEL 2013-03-22 12:25:21

回答

5

這個概念可以正常工作,您只要有語法生成代表錯了,你想有一個Func<PlayGrid, Color, Shape>不是Action

var constList = new List<Func<PlayGrid, Color, Shape>>(); 
constList.Add((pg, c) => new SShape(pg, c)); 

PlayGrid playgrid = /* however you get this */; 
Color color = /* however you get this */; 
var shape = constList[randomIdx](playgrid, color); 
+0

當我想創建一個新的對象時,我該如何打電話給承包商? – SIMEL 2013-03-22 12:27:48

+0

@IlyaMelamed答案已更新,以說明是的,您確實在意構造函數返回的對象。 – MattW 2013-03-22 12:32:01

+0

該約束器需要參數,並且我不能將'constList.Add(()=> new SShape());'添加到列表中,因爲它要求我輸入參數。但是,每次創建對象時都需要更改這些參數,因此在將構造函數添加到列表中時無法放入參數。 – SIMEL 2013-03-23 18:34:33

0

我相信你想創建一個Interface(也許是「IShape的」)對於所有形狀,然後使用factory來實例化它們(在此時您可以隨機實例化實現您的IShape接口的任何類型)。

0

以這種方式創建隨機對象的責任不應該是對象本身。我建議你create a factory來管理這個。您的工廠可以生成構造函數調用列表(或預先緩存對象),然後在其create方法中提供其中的一個。你的工廠應該返回構造的對象(可能是一個接口,如IShape),而不是調用來創建對象的動作。這樣,如果您的工廠需要注入依賴關係或設置其他值,則可以這樣做並管理對象的構建。另外,如果這是.NET Action類,我猜你的Shape類不能從它繼承,但是從你的問題中我不清楚「我得到的錯誤」是什麼。

這是關於在您的基類中使用GetRandomShape()方法的註釋。你不需要這樣做,因爲那時你的基類知道並且依賴於它的子類,這違反了OO設計實踐。

+0

我認爲這段代碼是爲工廠提供的 – Natrium 2013-03-22 12:28:15

0

您可以將類的類型保存到列表中,並使用Activator.CreateInstance(Type)來調用新實例。

或者您創建一個Shape類型的列表,添加每個類的一個實例並使用.Clone()方法來獲取新實例。您可以執行factory pattern

+0

你沒有看到這個問題 – Natrium 2013-03-22 12:36:30

2

你可以做這樣的事情:

public class ShapeFactory() 
{ 
    //list of shape constructor functions 
    private List<Func<Shape>> constructors; 

    //static initalizaton of the constructor list 
    static ShapeFactory() 
    { 
     constructors = new List<Func<Shape>>(); 
     constructors.Add(() => new OShape()); 
     constructors.Add(() => new SShape()); 
     constructors.Add(() => new LShape()); 
     .... 
    } 

    public static Shape CreateRandomShape() 
    { 
     int index = ...get random index somehow... 
     return constructors[index](); 
    } 
} 

和代碼

Shape randomShape = ShapeFactory.CreateRandomShape(); 
0

這是你開始有什麼延續使用它。它使用Reflection來調用構造函數。最初的列表是一個類型列表,而不是Actions。

class Program 
    { 
     static void Main(string[] args) 
     { 


      //register the types 
      List<Type> types = new List<Type>() { typeof(OShape), typeof(PShape), typeof(RShape) }; 

      // randomly select one 
      Type type = types[1]; 

      // invoke the ctor 
      ConstructorInfo ctor = type.GetConstructor(/*optional param for ctor, none in this case*/ new Type[] {}); 
      object instance = ctor.Invoke(new object[] {}); 

      // you can safely cast to Shape 
      Shape shape = (Shape)instance; //this is a PShape! 

     } 
    } 

    class Shape 
    { 
    } 

    class OShape : Shape 
    { 
    } 

    class PShape : Shape 
    { 
    } 

    class RShape : Shape 
    { 
    } 
} 

接下來要考慮的是如何允許Shape的子類型接收參數。你需要一個工廠模式,即一個對象,knoes如何構建其他對象,並根據會這麼做 - 例如 - 一個字符串:

Shape s = Factory.GetShape("OShape", new[] object {4}); 

檢查this question出來。

+1

你這樣做的方式,除了在版本3之前使用C#編譯器之外,我認爲使用反射沒有任何好處。您還沒有消除對形狀的難以理解的引用,所以您的反思只是簡單地按照問題試圖在正確完成時所做的基於委託的方法進行,只有_much_更慢。如果你引入了類似[MEF](http://msdn.microsoft.com/en-us/library/dd460648.aspx)的東西來刪除對Shape實現的依賴關係,那對我來說會更有意義。 – MattW 2013-03-22 13:01:18

+1

提及MEF的+1 :)實際上,我的解決方案有一個優勢 - 它支持帶參數的ctors,而不像所有其他依賴於Func的答案。 – 2013-03-23 18:24:03

相關問題