Неуниверсальные версии универсальных классов и интерфейсов

StackOverflow https://stackoverflow.com/questions/1005913

  •  05-07-2019
  •  | 
  •  

Вопрос

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

interface ICanCreate<T>
{
    T NewObject();
}

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

public class Factory
{
    private Dictionary<Type, ICanCreate> mappings; // what do I put here????

    public void RegisterCreator<T>(ICanCreate<T> creator)
    {            
    }

    public T Create<T>()
    {            
    }
}

В словаре какой тип я использую для моего значения? Я не знаю, пропускаю ли я какой-то принцип проектирования, и я знаю, что это во многом связано с ко (ntra?) Дисперсией. Любая помощь или идеи будут высоко оценены.

Это было полезно?

Решение

Вы должны либо просто использовать object в объявлении словаря (все это конфиденциально, и вы можете убедиться, что вы никогда не поместите туда неправильные вещи), либо объявить не -общий ICanCreate интерфейс, который ICanCreate<T> расширяется.

По сути, вам нужны отношения типа, которые не могут быть выражены в C # - и всякий раз, когда это происходит, вы получаете немного неприятное решение, но похоже, что вы можете изолировать уродство здесь (то есть сохранить его в одном классе ).

Другие советы

Интересно, что эта проблема решена в C # 4.0:

public interface ICanCreate<out T> // covariant
{
    T NewObject();
}

public class Factory
{
    private Dictionary<Type, ICanCreate<object>> mappings = new Dictionary<Type, ICanCreate<object>>();

    public void RegisterCreator<T>(ICanCreate<T> creator) where T:class
    {            
      mappings[typeof(T)] = creator;
    }

    public T Create<T>()
    {            
      ICanCreate<object> creator = mappings[typeof(T)];
      return (T) creator.NewObject(); // I do not think you can get rid of this cast
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top