Aangepaste IOC-container - hulp nodig bij 2/3 soorten

Achtergrond

Om mijn begrip van IOC te helpen verbeteren en hoe het te gebruiken, wil ik een voorbeeld maken van alle drie de IOC-technieken: Constructor-injectie, Setter-injectie en Interface-injectie zonder een raamwerk van derden te hoeven gebruiken. Ik denk dat ik een basisch voorbeeld heb van de injectie van een constructeur, maar worstelen met setter en interface-injectie.

Mijn vraag

Hoe zou je de aanpak van de schrijfinterface en de injectie van de setter benaderen?

Hier zijn mijn gedachten, laat het me weten als ik op de goede weg ben.

Interface injectie:

  1. Doorloop opgeloste objecten omgeleid met constructorinjectie, controleer welke interfaces zijn geïmplementeerd in interfaceDependencyMap
  2. Definieer een soort interfaceDependencyMap om een ​​interface aan de implementatie te koppelen.
  3. Los de implementatie op met behulp van interfaceDependencyMap
  4. Ken de juiste eigenschap toe aan het object dat is geïnitialiseerd met constructorinjectie

Setter injectie:

  1. Doorloop opgeloste objecten omgeleid met constructorinjectie
  2. Definieer een soort van setterInjectionMap
  3. Los de verwachte parameter op vanuit MethodInfo met behulp van de constructortoewijzingen
  4. Roep de methode van de methode setter op in het opgeloste parameterobject

Dit is wat ik tot nu toe heb gedaan voor de injectie van constructeurs

public class Program
{
    static void Main(string[] args)
    {
        //
        //instead of doing this:
        //
        //ICreditCard creditCard = new Visa();
        //var customer = new Customer(creditCard);
        //customer.Charge();


        var resolver = new Resolver();

        //map the types in the container
        resolver.Register();
        resolver.Register();

        //because the customer constructor has an ICreditCard parameter
        //our container will automatically instantiate it recursively
        var customer = resolver.Resolve();

        customer.Charge();

    }
}

public interface ICreditCard
{
    string Charge();
}

public class Visa : ICreditCard
{
    public string Charge()
    {
        return "Charging Visa";
    }
}

public class MasterCard : ICreditCard
{
    public string Charge()
    {
        return "Charging MasterCard";
    }
}

public class Customer
{
    private readonly ICreditCard _creditCard;

    public Customer(ICreditCard creditCard)
    {
        this._creditCard = creditCard;
    }

    public void Charge()
    {
        _creditCard.Charge();
    }
}


public class Resolver
{
    private Dictionary dependencyMap = new Dictionary();

    public T Resolve()
    {
        return (T) Resolve(typeof (T));
    }

    private object Resolve(Type typeToResolve)
    {
        Type resolvedType = null;

        try
        {
            resolvedType = dependencyMap[typeToResolve];
        }
        catch
        {
            throw new Exception(string.Format("could not resolve type {0}", typeToResolve.FullName));
        }

        var firstConstructor = resolvedType.GetConstructors().First();
        var constructorParameters = firstConstructor.GetParameters();
        if (constructorParameters.Count() == 0)
            return Activator.CreateInstance(resolvedType);

        IList parameters = constructorParameters.Select(parameterToResolve => Resolve(parameterToResolve.ParameterType)).ToList();

        return firstConstructor.Invoke(parameters.ToArray());
    }

    public void Register()
    {
        dependencyMap.Add(typeof (TFrom), typeof (TTo));
    }
}




5
En wat is de vraag?
toegevoegd de auteur svick, de bron
Dat kun je niet, althans niet direct. Maar als anderen (met een voldoende hoge rep) denken dat het bewerkte antwoord nu een echte vraag is, kunnen ze stemmen om opnieuw te openen. Of je kunt het markeren voor aandacht van de moderator met een aangepast bericht.
toegevoegd de auteur svick, de bron
@EricRomanowski: zie de redenen hieronder waarom de vraag werd afgesloten; als je die redenen in je vraag kunt aanpakken, dan kunnen anderen stemmen om het te laten heropenen, ervan uitgaande dat ze vinden dat het voldoet aan de normen voor vragen over SO.
toegevoegd de auteur casperOne, de bron
Kan ik dit op een andere manier heropenen?
toegevoegd de auteur Eric Walter, de bron
Ik heb mijn vraag opnieuw geformatteerd en opnieuw geformuleerd. Mijn excuses, ik heb een vraag geïmpliceerd in de achtergrondinformatie.
toegevoegd de auteur Eric Walter, de bron
blijkbaar is dit het best bewaarde geheim van C# =)
toegevoegd de auteur Eric Walter, de bron

1 antwoord

Is dit soort dingen waarnaar je op zoek bent?

class Container
{
    class Registration
    {
        public Type RegistrationType;
        public Func Resolver;
    }

    List registrations = new List();

    public object Resolve(Type type)
    {
        return registrations
            .First(r => type.IsAssignableFrom(r.RegistrationType))
            .Resolver(this);
    }

    public T Resolve()
    {
        return (T)Resolve(typeof(T));
    }

    public void Register(Func registration) where T : class
    {
        registrations.Add(new Registration()
        {
            RegistrationType = typeof(T),
            Resolver = registration
        });
    }
}

Gebruik:

interface IDependency
{
    string GetName();
}

class ConcreteDependency : IDependency
{
    public string GetName()
    {
        return "Concrete Dependency";
    }
}

class ConstructorExample
{
    readonly IDependency dependency;

    public ConstructorExample(IDependency dependency)
    {
        this.dependency = dependency;
    }

    public string GetString()
    {
        return "Consumer of " + dependency.GetName();
    }
}

class SetterExample
{
    public IDependency Dependency { get; set; }

    public string GetString()
    {
        return "Consumer of " + Dependency.GetName();
    }
}

[TestMethod]
public void MyTestMethod()
{
    var container = new Container();
    container.Register(c => new ConcreteDependency());
    container.Register(c => new ConstructorExample(c.Resolve()));
    container.Register(c => new SetterExample() { Dependency = c.Resolve() });

    var constructor = container.Resolve();
    Assert.AreEqual("Consumer of Concrete Dependency", constructor.GetString());

    var setter = container.Resolve();
    Assert.AreEqual("Consumer of Concrete Dependency", setter.GetString());
}

Als u meer geavanceerd wilt worden, raad ik u aan de bron van elk van deze te krijgen: SimpleInjector , Autofac , Ninject , StructureMap .

3
toegevoegd
Heel erg bedankt. Ik worstelde de laatste drie dagen om te proberen te achterhalen hoe de generieken voor de interface en setter te schrijven (niet zeker of dat de juiste terminologie is).
toegevoegd de auteur Eric Walter, de bron