假设我有一个服务的接口:

public interface IFooService
{
   void DoSomething();
}

和具体实现该服务,它是一个通用的:

public class FooService<TRequestingClass> : IFooService
{
   public virtual void DoSomething() { }
}

和予有需要IFooService的实例一些其他类:

public class Bar
{
   private IFooService _fooService;
   public Bar(IFooService fooService)
   {
      this._fooService = fooService;
   }
}

我需要线了我的IoC容器,从而获取创建栏时,它就会通过FooService接口<栏>的构造函数的参数。还有许多其他类一样吧。其中TRequestingClass是需要IFooService的实例类的类型每个可能还需要FooService接口传递给他们的一个实例。我不需要这个诡异暴露给消费者IFooService的。他们所应该关心的是,他们可以打电话,他们通过IFooService的方法。他们不应该需要知道,他们是通过IFooService的具体落实需要什么特别的构造。

这是可接受的alternatative到FooService接口将是具有在其constructur一个字符串参数包含它正在为创建的类的名字的非通用类。即:

public class FooService : IFooService
{
   public FooService(string requestingClassName) { }
}

我怎样才能线了我的IoC容器构建依赖这种方式?

如果你是困惑,为什么我会想这样一个奇怪的结构,可以考虑当你得到的是它和log4net.LogManager.GetLogger(typeof运算(SomeClass的))创建的ILog的log4net的是如何工作的最好的。我不想我的垃圾带的引用代码log4net的,所以我想编写一个简单的ILogger接口,并与像这样实现:

public class GenericLogger<T> : ILogger
{
    private readonly ILog log;

    public GenericLogger()
    {
        this.log = log4net.LogManager.GetLogger(typeof(T));
    }

    public void Debug(object message)
    {
        this.log.Debug(message);
    }

    /* .... etc ....  */
}
有帮助吗?

解决方案

在最简单的方式是创建一个ILogger<T>接口:

public class ILogger<T> : ILogger { }
public class GenericLogger<T> : ILogger<T> { ... }

然后依托通用的类型推断,以获得正确的类型。例如,在Ninject,下面的结合是所有你需要:

Bind(typeof(ILogger<>)).To(typeof(GenericLogger<>));

那么你的消费类型应该是这样的:

public class FooService : IFooService {
  public FooService(ILogger<FooService> logger) { ... }
}

如果你是坚决反对的ILogger<T>界面,你可以做一些更有创造性,就像一个自定义提供,其内容的IContext确定父类型。

public class GenericLogger : ILogger {
  public class GenericLogger(Type type) { ... }
}

public class LoggerProvider : Provider<ILogger> {
  public override ILogger CreateInstance(IContext context) {
    return new GenericLogger(context.Target.Member.ReflectedType);
  }
}

然后消耗类型将工作是这样的:

public class FooService : IFooService {
  public FooService(ILogger logger) { ... }
}

其他提示

如果我不是误解你,为什么不干脆让您的GericLogger构造带一个参数是对象的类型。然后这样做:

ILog = kernel.Get<ILog>(ParameterList);

我还没有Ninject参数列表读到完全还,但它似乎是注入使用IParameterList参数类型的一种方法。

编辑:

看起来这将工作是这样的:

ILog = kernel.Get<ILog>(new ConstructorArgument[] { 
    new ConstructorArgument("ClassName", this.GetType().Name) 
})

然后你有你的ILog

class GenericLogger : Ilog
{
    GenericLogger(string ClassName) {};
}

我没有测试这一点,只是似乎是从Ninject源(我看最近Ninject2树)

编辑:

您想通过ConstructorArgument,没有参数。更新,以反映。

此代码打印: “被叫由init”

class Init {
    public void Run() {
        StandardKernel kernel = new StandardKernel( new MyLoader() );
        kernel.Get<Tester>( new ConstructorArgument[] { 
            new ConstructorArgument( "ClassName", 
                this.GetType().Name 
            ) 
        } );            
    }
}

public class Tester {
    public Tester(string ClassName) {
        Console.WriteLine("Called From {0}", ClassName);
    }
}

编辑:

,这可能是有用的另一种方法是使用bind()。向()。WithConstructorArgument()结合,与任一的自粘结或用.WhenInjectedInto()条件下使用时可能是有用的。

要阐述的定义提供想法,这里有一个简单的方法来做到这一点...

internal class LogModule : StandardModule
    {
        private class log4netILogProvider : SimpleProvider<log4net.ILog>
        {
            protected override ILog CreateInstance(IContext context)
            {
                return LogManager.GetLogger(context.Instance.GetType());
            }
        }

        public override void Load()
        {
            Bind<log4net.ILog>().ToProvider(new log4netILogProvider());
        }
    }

然后,在类被注射:

[Inject]
        public ILog logger { get; set; }    
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top