首页 文章

运行时绑定:一个简单的任务运行器与ninject?

提问于
浏览
6

我正在编写一个简单的任务运行器应用程序 .

我有一堆实现ITask接口的类:

public interface ITask
{
   void Run();
}

我正在编写一个简单的控制台应用程序来创建ITasks实例,然后在每个应用程序上调用Run() . 任务实现使用构造函数注入,所以我想使用ninject .

我希望能够在运行时指定要运行哪些任务以及因此要激活哪些ITask实现 .

我想我可以将具体类型放入我的app.config然后在运行时我可以获得ninject从中构建一个ITask数组 . 如果做不到这一点,我可以指定我想在命令行上运行的任务 .

对我来说,这听起来像ninject的一个相当直接的案例,但我一直无法找到如何从配置或字符串绑定ninject .

任何人都能指出我正确的方向吗?

2 回答

  • 6

    对于ninject,extensions可以处理像xml配置这样的事情 .

    我要小心将Spring和Spring配置中的编程位混合起来 - 没有必要转移到XML配置只是为了让人们在.config文件中配置东西 . 我建议阅读一个XML配置节加载器,它在一个表示序列化的类中表示更高级别 .

    您将在Binding注册上使用metadata机制,然后指明如何根据该过程过滤任务集 .

    例如,重新利用@Ian Davis's answer(去读它并立即投票!):

    string metaDataKey = "key";
    kernel.Bind<IWeapon>().To<Shuriken>().WithMetadata(metaDataKey, true);
    kernel.Bind<IWeapon>().To<Sword>().WithMetadata(metaDataKey, false);
    kernel.Bind<IWeapon>().To<Knife>();
    
    bool? theOneIWant = null; // or true or false - i.e., the distillation of what your config says
    
    Func<IMetadata> myConfigSaysIWantOneLikeThatPredicate= metadata => 
        metadata.Has(metaDataKey) == theOneIWant != null
        && metadata.Get<bool>(metaDataKey) == theOneIWant.Value
    
    var weapons = kernel.Get<IEnumerable<IWeapon>>( myConfigSaysIWantOneLikeThatPredicate );
    // the above will generate a single item given the bindings above, but you get the picture - this generates an arbitrary length list
    
    foreach(var weapon in weapons)
        weapon.Fire();
    

    如果所有 WithMetadataWithMetadata 的简写替换为 Named() ,并且带有名称字符串参数的 .Get<T>() 的重载,这将使您实现@dave thieben的简单性,而不会将您的调用硬连接到类型名称 .

    编辑:示例,请参阅注释:

    using Ninject;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Xunit;
    
    namespace ninjectmess
    {
        public class Class1
        {
    

    一些垃圾类

    public interface ITask
            {
            }
    
            public class Aasdsdaadsdsa : ITask
            {
            }
            public class Bdsadsadasdsadsadsa : ITask
            {
            }
            public class Cddsadasdsadasdas : ITask
            {
            }
    

    实际测试

    [Fact]
            public void TestMethod()
            {
                var k = new StandardKernel();
                k.Bind<ITask>().To<Aasdsdaadsdsa>().Named( "A" );
                k.Bind<ITask>().To<Bdsadsadasdsadsadsa>().Named( "B" );
                k.Bind<ITask>().To<Cddsadasdsadasdas>().Named( "C" );
    
                var wanted = new string[] { "A", "C" };
    
                var tasks = k
                    .GetAll<ITask>( metadata => wanted.Contains( metadata.Name ))
                    .ToList();
                Assert.Equal( 2, tasks.Count );
                tasks.ForEach( Console.WriteLine );
            }
        }
    }
    
  • 3

    我喜欢Ruben的答案,但它可以像在命令行中使用所需任务的Type名称一样简单:

    public static void Main( string[] args )
    {
        var kernel = new StandardKernel();
        var tasks = new List<ITask>();
        foreach(var taskName in args)
        {
            tasks.Add( kernel.Get( Type.GetType( taskName ) ) );
        }
    
        doSomething(tasks);
    }
    

相关问题