Параметр ограничения условного типа - PullRequest
7 голосов
/ 25 июля 2011

У меня есть класс Container , у которого есть ContainerContents .Контейнер фактически принимает два параметра ограничения типа- TContainer - это тип контейнера, а TContents - тип содержимого, которое он принимает.

Я хочу убедиться, что если TContainer равен X или получен из X, то TContents также будет X или получен из X, но TContents не должен равняться TContainer.

I'mпытаясь выразить следующие вещи:

  • Вещи, которые можно носить (Swag), как карандаш.
  • Вещи, которые нельзя носить (BaseObject), как дерево.
  • Вещи, которые могут содержать другие вещи (Контейнер)
  • Контейнеры, которые нельзя перевозить, например, банковское хранилище.
  • Перевозимые контейнеры (например, рюкзак).

Если контейнер можно перевозить, то его содержимое также должно перевозиться.Но тот факт, что Контейнер является рюкзаком, не означает, что он может нести только рюкзаки.

Я хочу иметь возможность кодировать:

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

, но не var treeBag = new Container<Bag, Tree>();

Вот мои настройки скелета.

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;
    }
}

1 Ответ

3 голосов
/ 25 июля 2011

Я не думаю, что это сработает.

Я бы создал следующие интерфейсы:

interface ICarryable { }
interface IContainer<T> { }

Тогда вы могли бы реализовать следующие классы:

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

class Vault<T> : IContainer<T>
{  }

Если класс реализует ICarryable, его можно переносить.Если он не реализует этот интерфейс, это фиксированный объект, который не может быть перенесен.Это описывает более точно, что происходит.Ваш общий класс Container не сообщает, что контейнер имеет тип TContainer, а его содержимое имеет тип TContainerContents.

Чтобы не нарушать принцип DRY , выВы можете создать базовый класс контейнера, от которого унаследованы хранилище и рюкзак.Сделав его абстрактным, вы убедитесь, что никто не использует его вместо ваших конкретных реализаций.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...