Conditional type constraint parameter

I have a class, Container<T>, which has a ContainerContents<T>. The Container actually takes two type constraint parameters Container<TContainer,TContents> - TContainer being the type of the container, and TContents being the type of contents it accepts.

I want to ensure that if TContainer is X or derived from X, then TContents will also be X or derived from X, but that TContents does not have to equal TContainer.

I'm trying to express the following kinds of things.

  • Things that can be carried around (Swag), like a pencil.
  • Things that cannot be carried (BaseObject), like a tree.
  • Things that can hold other things (Container)
  • Containers that cannot be carried, like a bank vault.
  • Carriable Containers (like a backpack).
  • If a container can be carried, then its contents must be carriable too. But, just because the Container is a backpack doesn't mean it can only carry backpacks.

    I want to be able to code:

  • var ringWorld = new Container<BigRing, CivicWork>();
  • var pickleKnox = new Container<BankVault, Pickle>();
  • var swagBag = new Container<ToteBag, Swag>();
  • var tomeBag = new Container<ToteBag, Book>();
  • but not var treeBag = new Container<Bag, Tree>();

    Here's my skeletal setup.

    public abstract class BaseObject
    {
        private readonly string _name;
    
        protected BaseObject(string name)
        {
            _name = name;
        }
    
        public string Name { get { return _name; } }
    }
    public class Swag : BaseObject
    {
        private readonly int _weight;
    
        public Swag(string name, int weight):base(name)
        {
            _weight = weight;
        }
    
        public int Weight { get { return _weight; } }
    }
    /* I like the flexibility of i.e.: Container<BankVault,Pickles> 
    but if the container itself is carriable (Swag), then its contents 
    are by nature also carriable. */
    
    public class Container<TContainer,TContents> : BaseObject 
        where TContainer:BaseObject 
        where TContents:BaseObject, or Swag if TContainer:(Swag or derived from Swag)
    {
        ContainerContents<TContents> _contents;
    
        public Container(string name, int maxItems):base(name)
        {
    
            /* if (TContainer is derived from Swag) { TContents must be too } */
    
            _contents = new ContainerContents<TContents>(maxItems);
        }
    }
    public class ContainerContents<T> : List<T> where T : BaseObject
    {
        int _maxItems;
    
        public ContainerContents(int maxItems)
        {
            _maxItems = maxItems;
        }
    }

    I don't think this is going to work.

    I would create the following interfaces:

    interface ICarryable { }
    interface IContainer<T> { }
    

    Then you could implement the following classes:

    class Backpack<T> : ICarryable, IContainer<T>
    where T : ICarryable 
    {  }
    
    class Vault<T> : IContainer<T>
    {  }
    

    If a class implements ICarryable , it can be carried. If it doesn't implement that interface, it is a fixed object that can't be carried. This describes more precisely, what is going on. Your generic Container class doesn't communicate, that the container is of type TContainer and its contents are of type TContainerContents .

    To avoid violating the DRY principle, you can still create a generic container base class, your vault and backpack inherit from. Making it abstract ensures, that no one uses it instead of your concrete implementations.

    链接地址: http://www.djcxy.com/p/8652.html

    上一篇: 验证并提交表单而无需在无限循环中输入?

    下一篇: 条件类型约束参数