繁体   English   中英

在dll中动态调用方法时如何使用依赖注入(unity)?

[英]How to use Dependency Injection (unity) when dynamically invoke method in a dll?

我有一个项目,可以从dll动态调用方法。 dll名称在配置文件中定义。 下面是调用方法“运行”的代码。

Assembly a = Assembly.LoadFile(fullpath);
Type t = a.GetType(dll_fullname);
// Run in subclass
MethodInfo mi = t.GetMethod("Run");
if (mi != null)
{
    // set log file name
    object result = null;
    object classInstance = Activator.CreateInstance(t, null);
    object[] parametersArray = new object[] { t.Name };
    result = mi.Invoke(classInstance, parametersArray);
}
else
{
    myEventLog.WriteEntry("Error: Invoke DLL Failed.", EventLogEntryType.Error, (int)(SharedClass.EventId.Error));
}

每个DLL是一个类,该类从相同的基类MyTask继承,并覆盖方法Run。 现在,我们要在每个类中对Unity使用依赖注入。 显然,我们可以在每个DLL中应用Unity。 但是,我有一个问题:

由于所有DLL是从相同的基类MyTask继承的,因此在调用方法“运行”时是否可以进行依赖项注入? 我认为我们可以在CreateInstance传递注入参数时做到这一点。 但是,不同的DLL可能需要注入不同的服务。 所以,我被困在这里。

有人以前有过类似情况吗? 有什么建议么?

谢谢

由于要在运行时加载类型,因此需要工厂。 好吧,那个工厂可以接受相同的注射,然后将它们传递下去。 例如:

public class Factory : IFactory
{
    protected readonly IDependency1 _dependency1; //Injected
    protected readonly IDependency2 _dependency2; //Injected

    public Factory(IDependency1 dependency1, IDependency2 dependency2)
    {
        _dependency1 = dependency1;
        _dependency2 = dependency2;
    }

    public BaseClass Resolve(string libraryName, string typeName)
    {
        var assembly = Assembly.LoadFile(libraryName);
        var type = assembly.GetType(typeName);
        var args = new object [] { _dependency1, _dependency2 };
        return (BaseClass)Activator.CreateInstance(type, args);
    }
}

然后您注册工厂:

public static UnityContainer CompositionRoot()
{
    var container = new UnityContainer();
    container.RegisterType<IDependency1, Dependency1>();
    container.RegisterType<IDependency2, Dependency2>();
    container.RegisterType<IFactory,Factory>();
    return container;
}

并将其注入需要外部类的类中:

public class Application
{
    protected readonly IFactory _factory;

    public Application(IFactory factory)
    {
        _factory = factory;
    }

    public void Run()
    {
        var instance = _factory.Resolve("MyLibrary.dll", "External.DerivedClass");
        //Do something with instance
    }
}

依赖关系也很好地传递了。

如果发现不同的库需要不同的注入,则可以在工厂中管理所有逻辑,这就是这种逻辑所属的地方。

如果派生类型具有不同的构造函数参数和不同的注入,或者参数的顺序未知,则可以使用一些LINQ来解决依赖性,如下所示:

protected object TryInject(Type concreteType, IEnumerable<object> dependencies)
{
    var constructors = concreteType
        .GetConstructors
        (
            BindingFlags.Public | BindingFlags.Instance
        )
        .OrderByDescending
        (
            c => c.GetParameters().Length
        );
    foreach (var c in constructors)
    {
        var parameters = c.GetParameters();
        var arguments = parameters
            .Select
            (
                p => dependencies.FirstOrDefault
                (
                    d => p.ParameterType.IsAssignableFrom(d.GetType())
                )
            )
            .ToArray();
        if (!arguments.Contains( null ))
        {
            return Activator.CreateInstance(concreteType, arguments);
        }
    }
    return null;
}

然后只需将您的依赖项传递到数组中,它将确定需要哪些依赖项以及将它们放在哪里:

return (BaseClass)TryInject(type, args);

请参阅我在DotNetFiddle上的完整工作示例

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM