2013-03-22 50 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

相关问题