generics - 如何在 Kotlin 中为泛型类型创建 DI 绑定?
问题描述
我正在尝试找到一个基于 Kotlin 的依赖注入系统,该系统将允许我根据需要绑定诸如Foo<T>
和 resolve Foo<Int>
、Foo<String>
等泛型类型。
Kodein 似乎是更流行的 DI 框架之一,我已经研究过,但不知道它是如何可能的。Kodein 存储库中的Issue #83围绕该主题进行了一些讨论。
就我而言,我希望能够做这样的事情:
import com.atpgroup.testmaster.domain.ExecutableNode
import kotlin.reflect.KClass
annotation class TypeClass
annotation class Instance
/**
* Represents a catalog of nodes.
*
* Factory functions to generate nodes are initially registered to this catalog during setup and used to create
* instances of nodes.
*/
interface NodeCatalog {
fun <U : ExecutableNode> resolve(nodeType: KClass<U>, id: String): U
}
/**
* Simplifies resolution of nodes from a reified context.
*/
inline fun <reified T : ExecutableNode> NodeCatalog.resolve(id: String) = resolve(T::class, id)
/**
* Dummy implementation of a node catalog.
*/
class DummyNodeCatalog : NodeCatalog {
override fun <U : ExecutableNode> resolve(nodeType: KClass<U>, id: String): U = TODO("not implemented")
}
/**
* A type class representing the set of types that can behave like numbers.
*/
@TypeClass
interface Num<T>
// Int and Double both behave like numbers.
@Instance object IntNumInstance : Num<Int>
@Instance object DoubleNumInstance : Num<Double>
/**
* An executable node that adds two numbers together.
*
* @param T the type of the numbers that will be added together
*/
class AddNode<T>(override val id: String, private val N: Num<T>) : ExecutableNode {
override suspend fun execute() = TODO("not implemented")
}
// Resolve two "add nodes" that operate on different types of numbers.
val catalog = DummyNodeCatalog()
val addInts = catalog.resolve<AddNode<Int>>("integer adder")
val addDoubles = catalog.resolve<AddNode<Double>>("double adder")
在 C# 中,使用 Autofac 非常简单。下面的代码片段是我想要的 C# 中的一个工作实现:
using System;
using Autofac;
namespace Experiment
{
internal class Program
{
public static void Main()
{
var builder = new ContainerBuilder();
builder.RegisterType<IntNumInstance>().As<INum<int>>();
builder.RegisterType<DoubleNumInstance>().As<INum<double>>();
builder.RegisterGeneric(typeof(Add<>));
var container = builder.Build();
var addA = container.Resolve<Add<int>.Factory>()("add integers");
var addB = container.Resolve<Add<double>.Factory>()("add doubles");
Console.WriteLine(addA);
Console.WriteLine(addB);
Console.ReadLine();
}
}
interface INum<T> {}
class IntNumInstance : INum<int> {}
class DoubleNumInstance : INum<double> {}
class Add<T>
{
public delegate Add<T> Factory(string id);
public Add(string id, INum<T> N)
{
Id = id;
this.N = N;
}
public string Id { get; }
private INum<T> N { get; }
public override string ToString() => $"Add Node ({Id} - {N})";
}
}
输出
Add Node (add integers - Experiment.IntNumInstance)
Add Node (add doubles - Experiment.DoubleNumInstance)
解决方案
推荐阅读
- c# - 触发脚本运行
- common-table-expression - 递归查询如何加入递归成员查询
- kentico - Kentico 9 网络表单
- c - 如何在 openssl 库中设置最小和最大协议版本
- node.js - 如何使用 Client ID 和 Secret 对 API 调用者进行身份验证
- python - sklearn MinMaxScaler() 与 groupby pandas
- javascript - 只有买家才能在 Livewire:Laravel 中对产品进行评分
- python - 我怎样才能显示网络的边缘?
- scala - 用于 IO monad 的复杂 monad 转换器
- performance - API 变慢,Cassandra 节点上没有任何明显的瓶颈