TL; DR:Autofac是否支持类似AutoFixture fixture.Get()
机制的内容?
我使用Autofac并需要调用异步工厂方法,如下所示:
class AppModel
{
public static async Task<AppModel> CreateAsync(IDependency x, IDependency2 y)
{ ... }
}
我最简单的方法是执行这样的方法并让参数由Autofac 提供?即,我希望能够做到这样的事情:
Task<AppModel> creationTask = <some autofaccery>(AppModel.CreateAsync);
var appModel = await creationTask();
其中<some autofaccery>
表示与ContainerBuilder
和/或IContainer
和/或某种形式的generated Delegates或类似形式进行交互的一些机制,这些机制本质上是简洁的并且将我与明确指定工厂方法的参数。即,我想避免必须明确解决每个参数[和/或必须更新它们作为依赖项更改],就像我做atm:
var appModel = await AppModel.CreateAsync(
container.Resolve<IDependency>(),
container.Resolve<IDependency2>());
我位于基础架构组件区域,靠近组合根,并且可能以编程方式定义组件注册和/或做其他应该限制在那里的肮脏。我不介意反思,因为它只被调用一次。
重要的是,我确实需要Exception
发出的任何Task
来发现。
Task<T>
在很大程度上是一个红色的鲱鱼,但重点是遵循定义同步工厂方法的正常模式并让Autofac通过它不会飞(至少不直接) ),即我不能将其改为:
public static AppModel CreateAsync(IDependency x, IDependency2 y)
{ ... }
我也想避免两阶段初始化 - 我不需要该对象在初始化之前可用。
答案 0 :(得分:0)
(灵感来自TL; DR我在顶部添加)
您可以实施public static Task<T> ResolveAsync<T1, T>(Func<T1, Task<T>> func)
{
return func(_container.Resolve<T1>());
}
public static Task<T> ResolveAsync<T1, T2, T>(Func<T1, T2, Task<T>> func)
{
return func(_container.Resolve<T1>(), _container.Resolve<T2>());
}
public static Task<T> ResolveAsync<T1, T2, T3, T>(Func<T1, T2, T3, Task<T>> func)
{
return func(_container.Resolve<T1>(), _container.Resolve<T2>(), _container.Resolve<T3>());
}
系列方法: -
var appModel = await ResolveAsync<IDependency,IDependency2>(AppModel.CreateAsync);
这允许我这样做:
var appModel = await container.ResolveAsync<IDependency,IDependency2>(AppModel.CreateAsync);
或者显然这些可以变成扩展方法: -
<div class='draggable' id='something'>
<ul>
<li id='frank'>Frank</li>
<li id='Joe'>Joe</li>
</ul>
</div>
<br>
<br>
<div class='draggable' id='somethingElse'>
<div id='yes'>Yes</div>
<div id='no'>no</div>
</div>
处理一个包装器,允许使用C#的原始类型推理:(我将节省我的精力,而不是再花费更多时间来实现一个正确的解决方案在language/async paradigm not built for the job。
答案 1 :(得分:0)
除了需要一组丑陋的扩展方法之外,我的第一个答案是将工厂的签名泄漏到调用模块中,因此需要引用不直接需要的命名空间。为了隐藏它,可以使用相同的方案,但将依赖集封装在AsyncFactory
类中: -
class AppModel
{
public class AsyncFactory
{
public AsyncFactory(IDependency x, IDependency2 y)
{
CreateAsync = async() =>
new AppModel( x.CalculateA(await y.CalculateB()));
}
public Func<Task<AppModel> CreateAsync { get;}
}
private AppModel(A a) { ... }
}
然后调用者可以使用统一的机制来使用工厂: -
var appModel = await container.Resolve<AppModel.Factory>().CreateAsync();
(注意,没有重述参数类型,因此向AsyncFactory
添加更多依赖项不会触发对调用代码的连锁更改)
答案 2 :(得分:0)
滥用LazyTask<T>
,可以将LazyTask<T>
方法转换为Autofac 可以解析的内容: - 类型[源自class AppModel
{
public class AsyncFactory : LazyTask<AppModel>
{
public AsyncFactory(IDependency x, IDependency2 y) : base(async() =>
new AppModel( x.CalculateA(await y.CalculateB())))
{}
}
private AppModel(A a) { ... }
}
],看起来像这样:
var appModel = await container.Resolve<AppModel.AsyncFactory>();
可以按如下方式使用: -
Task<T> CreateAsync
不接受这一点,因为我仍然觉得有机会更清楚 - 即如果Autofac要对class AppModel
{
public async Task<AppModel> CreateAsync(IDependency x, IDependency2 y) =>
new AppModel( x.CalculateA(await y.CalculateB()));
}
方法采用特殊处理方法如下: -
Task<T>
自动将它们注册为类型Task
,允许按照以下方式使用它而不依赖于我的var appModel = await container.Resolve<Task<AppModel>>();
包装类型: -
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<link href="http://www.google.com/uds/modules/elements/transliteration/api.css" type="text/css" rel="stylesheet"/>
<script type="text/javascript">
// Load the Google Transliteration API
google.load("elements", "1", {
packages: "transliteration"
});
function onLoad() {
var options = {
sourceLanguage:
google.elements.transliteration.LanguageCode.ENGLISH,
destinationLanguage:
[google.elements.transliteration.LanguageCode.HINDI],
shortcutKey: 'ctrl+g',
transliterationEnabled: true
};
// Create an instance on TransliterationControl with the required
// options.
var control =
new google.elements.transliteration.TransliterationControl(options);
// Enable transliteration in the textbox with id
// 'transliterateTextarea'.
control.makeTransliteratable(['transliterateTextarea']);
}
google.setOnLoadCallback(onLoad);
</script>
</head>
<body>
Type in Hindi (Press Ctrl+g to toggle between English and Hindi)<br>
<a href="#" onclick="document.getElementById('Wrapper').style.display = 'block'; return false;">show textarea</a>
<div id="Wrapper" style="display:none"> <h2> Textarea </h2>
<textarea id="transliterateTextarea" style="width:600px;height:200px"></textarea>
<textarea id="transliterateTextarea2" style="width:600px;height:200px"></textarea>
</div>
</body>
</html>