Conditional Type Constraint Option

I have a class Container <T> that has ContainerContents <T>. A container actually accepts two restriction parameters of the type Container <TContainer, TContents> - TContainer is the type of container, and TContents is the type of content that it accepts.

I want to make sure that if TContainer is X or derived from X, then TContents will also be X or derived from X, but TContents should not equal TContainer.

I am trying to express the following things.

  • Things you can carry with you (Swag), like a pencil.
  • Things that can't be wrapped (BaseObject), like a tree.
  • Things that may contain other things (Container)
  • Containers that cannot be transported like bank vault.
  • Transportable containers (e.g. backpack).

If the container can be transported, its contents must also be loaded. But just because the Container is a backpack, this does not mean that 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 is my skeletal installation.

 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 ie: 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;
     }
 } 
+7
source share
1 answer

I do not think this will work.

I would create the following interfaces:

 interface ICarryable { } interface IContainer<T> { } 

Then you can implement the following classes:

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

If the class implements ICarryable , it can be migrated. If it does not implement this interface, it is a fixed object that cannot be transported. This more accurately describes what is happening. Your generic Container class does not report that the container is of type TContainer and its contents are of type TContainerContents .

In order not to violate the DRY principle, you can still create a common base class of the container on which your storage and backpack are inherited. Creating an abstract ensures that no one uses it instead of your specific implementations.

+3
source

All Articles