Я действительно ответил на свой вопрос.У Ninject было все необходимое для работы, но не из коробки.После вызова Bind () возвращается экземпляр IBindingToSyntax.У него есть метод с именем WithPropertyValue.Этот метод принимает значение или обратный вызов.Обратный вызов имеет экземпляр Ninject.Activation.IContext, который имеет IKernel, который, наконец, имеет метод Get.Итак ... Я могу посмотреть на тип свойства, названного в WithPropertyValue, захватить свойство, определить тип и затем получить обратный вызов Получить экземпляр для типа свойства.Фу.
Вот класс расширения, который я написал, чтобы помочь заполнить мои типизированные наборы репозиториев:
using System;
using System.Linq.Expressions;
using System.Reflection;
using Ninject;
using Ninject.Activation;
using Ninject.Planning.Targets;
using Ninject.Syntax;
namespace NinjectExtensions
{
/// <summary>
/// Provides extension methods for the BindingWithSyntax class.
/// </summary>
public static class BindingWithSyntaxExtensions
{
/// <summary>
/// Indicates that the specified property should be injected with the bound type of the property.
/// </summary>
/// <typeparam name="TBinding">The type of the object to set the property for.</typeparam>
/// <param name="instance">Used to add additional information to a binding.</param>
/// <param name="name">The name of the property.</param>
/// <returns>The instance that was passed in.</returns>
public static IBindingWithSyntax<TBinding> WithPropertyValue<TBinding>(this IBindingWithSyntax<TBinding> instance, string name)
{
if (instance == null)
{
throw new ArgumentNullException("instance");
}
PropertyInfo propertyInfo = typeof(TBinding).GetProperty(name);
if (propertyInfo == null)
{
throw new ArgumentException("There was not a public property with the given name.", "name");
}
Func<IContext, object> callback = context => context.Kernel.Get(propertyInfo.PropertyType);
return instance.WithPropertyValue(name, callback);
}
/// <summary>
/// Indicates that the specified property should be injected with the bound type of the property.
/// </summary>
/// <typeparam name="TBinding">The type of the object to set the property for.</typeparam>
/// <typeparam name="T">The type of the property.</typeparam>
/// <param name="instance">Used to add additional information to a binding.</param>
/// <param name="propertyGetter">An expression yielding the property to set the value to.</param>
/// <returns>The instance that was passed in.</returns>
public static IBindingWithSyntax<TBinding> WithPropertyValue<TBinding, T>(this IBindingWithSyntax<TBinding> instance, Expression<Func<TBinding, T>> propertyGetter)
{
if (instance == null)
{
throw new ArgumentNullException("instance");
}
if (propertyGetter == null)
{
throw new ArgumentNullException("propertyGetter");
}
PropertyInfo propertyInfo = getPropertyInfo(typeof(TBinding), propertyGetter);
Func<IContext, object> callback = context => context.Kernel.Get<T>();
return instance.WithPropertyValue(propertyInfo.Name, callback);
}
/// <summary>
/// Indicates that the specified property should be injected with the given value.
/// </summary>
/// <typeparam name="TBinding">The type of the object to set the property for.</typeparam>
/// <typeparam name="T">The type of the property.</typeparam>
/// <param name="instance">Used to add additional information to a binding.</param>
/// <param name="propertyGetter">An expression yielding the property to set the value to.</param>
/// <param name="value">The value to set the property to.</param>
/// <returns>The instance that was passed in.</returns>
public static IBindingWithSyntax<TBinding> WithPropertyValue<TBinding, T>(this IBindingWithSyntax<TBinding> instance, Expression<Func<TBinding, T>> propertyGetter, T value)
{
if (instance == null)
{
throw new ArgumentNullException("instance");
}
if (propertyGetter == null)
{
throw new ArgumentNullException("propertyGetter");
}
PropertyInfo propertyInfo = getPropertyInfo(typeof(TBinding), propertyGetter);
return instance.WithPropertyValue(propertyInfo.Name, value);
}
/// <summary>
/// Indicates that the specified property should be injected with the value returned by the callback.
/// </summary>
/// <typeparam name="TBinding">The type of the object to set the property for.</typeparam>
/// <typeparam name="T">The type of the property.</typeparam>
/// <param name="instance">Used to add additional information to a binding.</param>
/// <param name="propertyGetter">An expression yielding the property to set the value to.</param>
/// <param name="callback">A function to call to retrieve the value to set the property to.</param>
/// <returns>The instance that was passed in.</returns>
public static IBindingWithSyntax<TBinding> WithPropertyValue<TBinding, T>(this IBindingWithSyntax<TBinding> instance, Expression<Func<TBinding, T>> propertyGetter, Func<IContext, T> callback)
{
if (instance == null)
{
throw new ArgumentNullException("instance");
}
if (propertyGetter == null)
{
throw new ArgumentNullException("propertyGetter");
}
if (callback == null)
{
throw new ArgumentNullException("callback");
}
PropertyInfo propertyInfo = getPropertyInfo(typeof(TBinding), propertyGetter);
Func<IContext, object> baseCallback = context => callback(context);
return instance.WithPropertyValue(propertyInfo.Name, baseCallback);
}
/// <summary>
/// Indicates that the specified property should be injected with the value returned by the callback.
/// </summary>
/// <typeparam name="TBinding">The type of the object to set the property for.</typeparam>
/// <typeparam name="T">The type of the property.</typeparam>
/// <param name="instance">Used to add additional information to a binding.</param>
/// <param name="propertyGetter">An expression yielding the property to set the value to.</param>
/// <param name="callback">A function to call to retrieve the value to set the property to.</param>
/// <returns>The instance that was passed in.</returns>
public static IBindingWithSyntax<TBinding> WithPropertyValue<TBinding, T>(this IBindingWithSyntax<TBinding> instance, Expression<Func<TBinding, T>> propertyGetter, Func<IContext, ITarget, T> callback)
{
if (instance == null)
{
throw new ArgumentNullException("instance");
}
if (propertyGetter == null)
{
throw new ArgumentNullException("propertyGetter");
}
if (callback == null)
{
throw new ArgumentNullException("callback");
}
PropertyInfo propertyInfo = getPropertyInfo(typeof(TBinding), propertyGetter);
Func<IContext, ITarget, object> baseCallback = (context, target) => callback(context, target);
return instance.WithPropertyValue(propertyInfo.Name, baseCallback);
}
private static PropertyInfo getPropertyInfo<T>(Type bindingType, Expression<T> expression)
{
if (expression.Body.NodeType != ExpressionType.MemberAccess)
{
throw new ArgumentException("The expression did access a property.", "propertyGetter");
}
MemberExpression memberExpression = (MemberExpression)expression.Body;
if (memberExpression.Member.MemberType != MemberTypes.Property)
{
throw new ArgumentException("The expression did not access a property.", "propertyGetter");
}
PropertyInfo propertyInfo = (PropertyInfo)memberExpression.Member;
if (!propertyInfo.DeclaringType.IsAssignableFrom(bindingType))
{
throw new ArgumentException("The expression did not access a property in the specified type.", "propertyGetter");
}
return propertyInfo;
}
/// <summary>
/// Injects every property with the bound type of the property.
/// </summary>
/// <typeparam name="TBinding">The type of the object to set the property for.</typeparam>
/// <param name="instance">Used to add additional information to a binding.</param>
/// <returns>The instance that was passed in.</returns>
public static IBindingWithSyntax<TBinding> SetAllProperties<TBinding>(this IBindingWithSyntax<TBinding> instance)
{
if (instance == null)
{
throw new ArgumentNullException("instance");
}
IBindingWithSyntax<TBinding> result = instance;
foreach (PropertyInfo property in typeof(TBinding).GetProperties())
{
PropertyInfo local = property;
result = result.WithPropertyValue(local.Name, context => context.Kernel.Get(local.PropertyType));
}
return result;
}
}
}
Это позволяет мне настраивать типизированный набор репозиториев следующим образом:
Bind<IMyRepository>().To<MyRepository>();
Bind<MyRespositorySet>().ToSelf()
.WithPropertyValue(set => set.MyRepository);
Я также потратил некоторое время на создание модуля Module, чтобы избавить меня от необходимости создавать отдельный класс Module для каждого написанного мной модульного теста.Но это довольно большой кусок кода, поэтому я его опущу.