实现特定接口的类型的集合

时间:2015-03-24 16:34:53

标签: c#

我正在尝试使用名称ForumHolderAdminController创建一个类。 ForumHolderAdminController为父类CmsAdminController提供了一组控制器类型。

我有以下代码:

public abstract class CmsAdminController : Controller {
    // The type of child controllers allowed
    protected Collection<Type> AllowedChildren {
        get { return null; }
    }
}

public class ForumHolderAdminController : CmsAdminController {
    protected new Collection<Type> AllowedChildren {
        get {
            Collection<Type> allowedChildren = new Collection<Type> {
                typeof(ThreadHolderController)
            };
            return allowedChildren;
        }
    }
}

我想限制开发人员传递实现IController接口的类型集合。类似于以下内容:

protected new Collection<IController> AllowedChildren {
        get {
            Collection<IController> allowedChildren = new Collection<IController> {
                typeof(ThreadHolderController)
            };
            return allowedChildren;
        }
    }

显然,代码示例不起作用,因为没有创建实例。但我想要一些类似的东西,你不必创建一个对象的实例,你只需要传递该类型。

我确实看到以下问题似乎有点相关,但其中一条评论建议在将类型添加到集合之前使用类型的静态分析: Type-safe collection of Type class with defined base type

如果我必须执行静态分析,这会让我遇到问题。如果开发人员通过了一个没有实现IController接口的类型,那么在执行之前我们不会知道代码存在问题。我希望有一个编译错误,阻止开发人员传递一个或多个不实现IController接口的类型集合。

因此,是否可以限制开发人员传递实现IController接口的类型集合?

2 个答案:

答案 0 :(得分:1)

通过返回包装Type的自定义类,您可以非常接近您想要做的事情,并且只能为实现IController的泛型类型实例化:

public class ControllerTypeWrapper<T> : ControllerTypeWrapper
    where T : IController
{
    public Type Type {get {return typeof(T);}}
}

public class ControllerTypeWrapper
{
    // This should only be extended by ControllerTypeWrapper<T>
    internal ControllerTypeWrapper(){}
}

然后您的AllowedChildren property should return these wrappers, and whatever's consuming it can simply use the。类型`属性取消结果:

protected new IReadOnlyCollection<ControllerTypeWrapper> AllowedChildren {
   get {
       return new List<ControllerTypeWrapper> {
           new ControllerTypeWrapper<ThreadHolderController>()
       };
   }
}
  

注意:您可能实际上并不打算将此属性设为new。考虑创建父类的属性abstract,以便可以强制子类到override

另一个选择是使用Alex Voskresenskiy的方法,使用RegisterType<T>()方法,但在这种情况下,您可能希望该方法受到保护,并期望您的子类的构造函数调用RegisterType<>()你想要允许的任何孩子类型。这样做的不足之处在于,每次构造控制器时你都会做这项工作,而你可能只需要它一次。

可能有其他甚至更好的选项,例如使用自定义属性和使用简单的单元测试来检查所有控制器上的所有属性是否都包含相应的类型。但是如果不了解更多关于如何使用这些数据的话,很难说。

答案 1 :(得分:0)

我不确定我是否正确,但你可以这样做:

public abstract class CmsAdminController : Controller
{
    private Collection<Type> _allowedChildren = new Collection<Type>();
    // The type of child controllers allowed
    protected Collection<Type> AllowedChildren
    {
        get {return _allowedChildren; }
    }

    public void Registertype<T>() where T : IController
    {
        _allowedChildren.Add(typeof(T));
    }
}

您唯一应该做的就是限制_allowedChildren上的Add,例如,您可以返回IEnumerable而不是Collection