派生子类的集合

时间:2010-11-21 02:50:32

标签: c# inheritance collections

是否有一种可接受的方法可以将可能派生的对象添加到集合而不用允许自己创建基础或派生对象的实例?我认为这几乎是矛盾的。

关于我能够提出的唯一方法是从子基础实现中添加父集合,如下所示:

// Child constructors
private void Child() { }
protected void Child(Parent parent)
{
    parent.Collection.Add(this);
}

这会强制子对象始终使用父对象进行实例化,但是将子类添加到来自子对象的父集合似乎是一个相当混乱的实现。我知道我可以将Type-type变量传递给方法,这可能是要走的路,但我不知道如何创建/强制转换为传递的类型。


更新:我正在使用看似这样的代码作为可能的通用ChildCollection.Add方法,如果这样可以让任何人更好地了解我想要的东西......我们会看到它是否能够长时间工作运行:

// Currently testing directly in Parent class;
// can later be moved/modified for Parent's ChildCollection class.
public Child AddTest(string info, Type derivedType)
{
    ConstructorInfo ci = derivedType.GetConstructor(new Type[] { typeof(Parent) });
    Child myBaby = (Child) ci.Invoke(new Object[] { this });
    myBaby.Initialize(info);
    return myBaby;
}

然后可以使用以下代码调用它:

Child newChild = Parent.AddTest("Hello World", typeof(DerivedChild));

3 个答案:

答案 0 :(得分:1)

限制是没有父对象就不应该存在子对象。如何公开像“IsAttached”或“Parent”这样的属性并使用内部方法将子对象附加到父对象?然后可以在代码库中的任何位置构造子对象,但在附加之前它们不会是有效的子对象。

- internal Attach(parent) 
- internal Detach() 
- public IsAttached

然后,父集合可以实现添加子对象和执行某些验证的方法。我正在思考形式和控制。

Collection.Add(child) 
{
    // throw error if the child is not the right type
    child.Attach(this)
    base.add(child)    
} 

答案 1 :(得分:1)

最终,我的代码与我在更新中发布的代码非常相似。我在这里发布它,因为我认为它对于通用对象工厂或有限的工厂(在这种情况下,仅限于从Child类派生的那些)是一种有用的技术。

基本思想是创建一个自定义集合,然后使用Add方法(或者我应该将其命名为Create?)来实例化对象并正确处理Child衍生中的任何重写初始化。

这是我最终得到的代码的骨架:

// Use standard Child
public Child Add(string initInfo)
{
    Child newChild = new Child(this.Parent);
    // There's actually a bit more coding before Initialize()
    // in the real thing, but nothing relevant to the example.
    newChild.Initialize(initInfo);
    List.Add(newChild);
    return newChild;
}

// Overload for derived Child.
public Child Add(Type childDerivative, string initInfo)
{
    if (!childDerivative.IsSubclassOf(typeof(Child)))
        throw new ArgumentException("Not a subclass of Child.");
    ConstructorInfo ci = childDerivative.GetConstructor(
        BindingFlags.Instance |
        BindingFlags.Public | BindingFlags.NonPublic |
        BindingFlags.FlattenHierarchy |
        BindingFlags.ExactBinding, 
        null, new Type[] { typeof(Parent) }, null);
    if (ci == null)
        throw new InvalidOperationException("Failed to find proper constructor.");
    newChild = (Child)ci.Invoke(new Object[] { this.Parent });
    newChild.Initialize(initInfo);
    List.Add(newChild);
    return newChild;
}

由于这可能无法覆盖客户端应用程序可能想要创建的每个可能派生的Child(特别是如果他们将自己的参数添加到构造函数中),我想我可能还会提供Add(Child child)方法,但需要注意的是,如果用户使用标准的“new Child(Parent)”实例化Child对象,则他们还负责以预期的方式执行所有标准初始化步骤。

答案 2 :(得分:0)

如果您认真考虑不需要能够创建父类型的实例,只需使其构造函数受到保护或将其声明为抽象。

然后,您可以创建子类实例并轻松地将它们添加到列表中,并且无法创建基类的实例。