Общее решение простых классов + фабрика - PullRequest
3 голосов
/ 28 июня 2010

Мой крошечный разум не может придумать элегантного решения этой проблемы.Предположим, у меня есть такой класс:

    public class Foo<T>
    {
        public RecordType Type { get; set; }
        public T Value { get; set; }
    }

Где RecordType может выглядеть примерно так:

 public enum RecordType
    {
        EmptyRecord,
        BooleanRecord,
        IntegerRecord,
        StringRecord,
        ByteRecord
    }

Цель состоит в том, чтобы обрабатывать IEnumerable<Foo<T>> равномерно для итерации и/ или включить RecordType и выполнить действие, избегая при этом упаковки внутренних типов, если это вообще возможно.Кроме того, было бы неплохо использовать фабрику для создания этих Foo от фабричного метода.

Я возился с несколькими быстрыми реализациями общности в базовом классе или интерфейсе и ничегопридумал ответ на эту, казалось бы, очень простую проблему изящно.

Небольшое редактирование: Я должен был упомянуть, что моей основной целью является использование .Value без навязывания вызывающей стороны.

1 Ответ

2 голосов
/ 28 июня 2010

Вы можете ввести неуниверсальный интерфейс IFoo:

public interface IFoo
{
    RecordType Type { get; set; }
}

, который реализуется универсальным классом Foo:

public class Foo<T> : IFoo
{
    public T Value { get; set; }
}

и создайте фабричный метод, который создает экземпляр Foo в зависимости от RecordType:

public static IFoo CreateFoo(RecordType type)
{
    switch (type)
    {
        case RecordType.Bool: return new Foo<bool>();
        // ...
    }
}

После того, как вы создали экземпляр Foo таким способом, вы еще не можете получить доступ к значению, потому что вы еще не знаете параметр типа. Но вы можете проверить тип с помощью свойства Type и выполнить соответствующее приведение:

IFoo foo = CreateFoo(RecordType.Bool);

if (foo.Type == RecordType.Bool)
{
    Foo<bool> boolFoo = (Foo<bool>)foo;
    bool value = boolFoo.Value;
}

Если у вас есть метод, который работает с объектами Foo, например:

void DoIt<T>(IEnumerable<Foo<T>> foos)
{
    foreach (Foo<T> foo in foos)
    {
        Qux(foo.Value);
    }
}

и имея множество объектов IFoo, вы можете использовать Cast / OfType, которые:

IEnumerable<IFoo> foos = // ...
DoIt<bool>(foos.OfType<Foo<bool>>());

Итак, по сути, вы используете Foo , когда вы знаете T во время компиляции, и IFoo, если вы знаете T только во время выполнения. IFoo требует проверки, чтобы превратить его в Foo для некоторого T во время выполнения.

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