How to use convention extension with complex initiation ( like: ToMethod )

140 Views Asked by At

example of convention extension

kernel.Bind(x =>
{
    x.FromThisAssembly()
     .SelectAllClasses()
     .WithAttribute<SomeAttribute>()
     .BindBase();
});

And each type which I get should be provide complex initiation with this method

 public static IPage GetInstance(Type type)
        {         
            MethodInfo method = typeof(PageService).GetMethod("Create");
            IPage page = (IPage)method.MakeGenericMethod(type).Invoke(null, new object[] { null });
            return page;
        }
2

There are 2 best solutions below

4
On

Create a IBindingGenerator:

public class MyBindingGenerator : IBindingGenerator
{
    public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(
        Type type,
        IBindingRoot bindingRoot)
    {
        yield return bindingRoot
            .Bind(type)
            .ToMethod(ctx => GetInstance(type));
    }

    public static object GetInstance(Type type)
    {
        MethodInfo method = typeof(PageService).GetMethod("Create");
        return method.MakeGenericMethod(type).Invoke(null, new object[] { null });
    }
}

and use it as follows:

kernel.Bind(x =>
{
    x.FromThisAssembly()
     .SelectAllClasses()
     .WithAttribute<SomeAttribute>()
     .BindWith<MyBindingGenerator>();
});
1
On

After some searching of examples , I have written this solutions. I do not know is it the best solution, but any way it is works for me. If somebody will improve my code or write best practice for my question I will be grateful :-)

UnitTest Where I want get type which Inherited From IStepContext, which have MarkAttribute

[TestClass]
public class Test
{
    private readonly IKernel _kernel = new StandardKernel();

    [TestInitialize]
    public void Startup()
    {           
        _kernel.Bind(a =>
        {
            a.FromThisAssembly()
                .SelectAllClasses()
                .InheritedFrom<IStepContext>()
                .WithAttribute<MarkAttribute>(x => x.Type == Inheritance.Derived).BindWith<SettingsBindGenerator>();
        });
    }
    [TestMethod]
    public void BaseClass()
    {
        BaseClass1 derived1 = _kernel.Get<BaseClass1>();
        Type res = derived1.WhoIAm(); //-- - > "BaseClass1"
        Assert.AreEqual(res, typeof (BaseClass1));
    }

    [TestMethod]
    public void DerivedClass()
    {
        IStepContextA derived = _kernel.Get<IStepContextA>();
        Type res = derived.WhoIAm(); //-- - > "DerivedClass"
        Assert.AreEqual(res, typeof (DerivedClass));
    }

    [TestMethod]
    public void DerivedClassA1()
    {
        IStepContext derived2 = _kernel.Get<BaseClassA>();
        Type res = derived2.WhoIAm(); //-- - > "DerivedClass"
        Assert.AreEqual(res, typeof (DerivedClassA1));
    }
}

Custom BindGenerator

public class SettingsBindGenerator : IBindingGenerator
    {
        public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot)
        {
            Func<Type, IBindingWhenInNamedWithOrOnSyntax<object>> func =
                t => bindingRoot.Bind(t).ToMethod(ctx => GetInstance(ctx, type));


            var bindings = new List<IBindingWhenInNamedWithOrOnSyntax<object>>();

            // if type inherited from interface
            Type[] interfs = type.GetInterfaces();
            if (interfs.Length > 1)
            {
                // skip base interface (IStepContext)
                interfs = interfs.Take(interfs.Length - 1).ToArray();
                bindings = interfs.Select(x => func(x)).ToList();
            }

            // if type inherited from baseType
            Type baseType = type.BaseType;
            if (baseType != null)
            {
                bindings.Add(func(baseType));
                if (ShouldBeBound(baseType))
                {
                    var ancestor = baseType.BaseType;
                    while (ancestor != null && ShouldBeBound(ancestor))
                    {
                        bindings.Add(func(ancestor));
                        ancestor = ancestor.BaseType;
                    }
                }
            }
            return bindings;
        }

        private static bool ShouldBeBound(Type type)
        {
            return type.IsClass && type != typeof (object);
        }

        private object GetInstance(IContext ctx, Type type)
        {
            MethodInfo method = typeof(PageService).GetMethod("Create");
            IPage page = method.MakeGenericMethod(type).Invoke(null, new    object[] { null });        
            return page;   
        }
    }

Helper Classes

 public class BaseClass : AbstractStepContext
    {
        public override Type WhoIAm()
        {
            return GetType();
        }
    }

    public class AbstractStepContext : IStepContext
    {
        public virtual Type WhoIAm()
        {
            return GetType();
        }
    }

 public class BaseClass1 : IBase
    {
        public virtual Type WhoIAm()
        {
            return GetType();
        }
    }
 [Mark(Inheritance.Base)]
    public class BaseClass1Derivied : BaseClass1
    {
        public override Type WhoIAm()
        {
            return GetType();
        }
    }

public class BaseClassA : AbstractStepContext
    {
        public virtual Type WhoIAm()
        {
            return GetType();
        }
    }

[Mark(Inheritance.Derived)]
    public class DerivedClass : IStepContextA
    {

        public Type WhoIAm()
        {
            return GetType();
        }

    }

[Mark(Inheritance.Derived)]
    public class DerivedClassA1 : BaseClassA
    {
        public override Type WhoIAm()
        {
            return GetType();
        }
    }

 public interface IStepContext
    {
        Type WhoIAm();
    }
    public interface IStepContextA : IStepContext
    {       
    }

public class MarkAttribute : Attribute
    {
        public Inheritance Type ;
        public MarkAttribute(Inheritance type)
        {
            Type = type;
        }
    }