Как зарегистрировать универсальный класс для разрешения, когда универсальный аргумент основан на определенном типе? - PullRequest
0 голосов
/ 12 сентября 2011

Как мне зарегистрировать IPetFactory<TPet> для разрешения с помощью DefaultPetFactory<TPet>, где TPet может быть любым классом на основе Pet в приведенном ниже примере?

Я хотел бы иметь возможность разрешитьIPetFactory<Dog> с DefaultPetFactory<Dog>.

Я только что нашел примеры использования BasedOn, где сама Фабрика основана на классе, а не на общем аргументе.

class Pet
{
    public string Name { get; set; }
}

class Fish : Pet {}
class Dog : Pet {}
class Cat : Pet { }


interface IPetFactory<TPet>  where TPet : Pet;
class DefaultPetFactory<TPet> : IPetFactory<Pet> where TPet : Pet
{
    // default implementation
}

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

РЕДАКТИРОВАТЬ:

Я нашелпроблема была не в том, что я думал.Это было связано с общими аргументами и исключением из «арности определения универсального типа», которое вызвало мои проблемы.

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

Если я так сделаю, это не сработает.

class Owner
{

}

class DefaultPetFactory<TPet> : IPetFactory<Owner, TPet> where TPet : Pet
{
    // default implementation
}

Если я так сделаю, это будет:

class DefaultPetFactory<TOwner, TPet> : IPetFactory<TOwner, TPet> 
    where TOwner : Owner
    where TPet : Pet
{
    // default implementation
}

Если у кого-то есть лучшее решение дляэто, желательно с регистрациями, это ценится.Я не люблю менять классы, чтобы регистрация работала.

1 Ответ

2 голосов
/ 13 сентября 2011

(для уточненного вопроса)

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

В Windsor 3 вы можете обойти его, внедрив новый интерфейс с именем IGenericImplementationMatchingStrategy, выполнив примерно следующее (не проверено, я пишу это по памяти):

public class PetMatcher: IGenericImplementationMatchingStrategy
{
   public Type[] GetGenericArguments(ComponentModel model, CreationContext context)
   {
      if (SomePreconditionToMakeSureThatsReallyTheScenarioDescribedAbove() == false )
      {
         return null;// which will fallback to default behaviour
      }
      // implementation needs just one generic arg, second of two the interface has
      return new[]{ context.GenericArguments[1] };
   }
}

Затем вы регистрируете это следующим образом:

Container.Register(
    Classes.FromAssemblyContaining(typeof(IPetFactory<,>)).BasedOn(typeof(IPetFactory<,>))
        .WithServiceBase()
        .Configure(
            c => c.ExtendedProperties(
                Property.ForKey(ComponentModel.GenericImplementationMatchingStrategy)
                    .Eq(new PetMatcher()))));
...