我很欣赏这个问题标题可能有点含糊不清。我正在尝试使用我自己的功能启发类ResourceFactory<T>
来抽象电子邮件提供程序。所以ResourceFactory<T>
的工作方式是它的构造函数需要Func<T>
这是一个工厂来创建T
的实例。 ResourceFactory<T>
然后公开一个名为Using<T>(Action<T>)
的方法,该方法将采用Action<T>
,通过调用构造函数中传递给它的T
创建一个新的Func<T>
对象,在预定义的调度程序(例如线程池)上调用操作,然后在函数完成时处理创建的T
。
因此,我的电子邮件提供商期望在其构造函数中有ResourceFactory<SmtpClient>
的实例。它也可以重载以接受名为from
的字符串,该字符串是电子邮件的发件人地址。代码如下:
public class DotNetEmailProvider : IEmailProvider
{
// TODO: Don't hard-code the CC
private readonly ResourceFactory<SmtpClient> _smtpFactory;
private readonly MailAddress _from;
/// <summary>
/// Create the DotNetEmailProvider.
/// </summary>
/// <param name="factory"></param>
public DotNetEmailProvider(ResourceFactory<SmtpClient> factory) : this(factory, "support@rumm.co.uk") { }
/// <summary>
/// Create the DotNetEmailProvider.
/// </summary>
/// <param name="factory"></param>
/// <param name="from"></param>
public DotNetEmailProvider(ResourceFactory<SmtpClient> factory, string from)
{
_smtpFactory = factory;
_from = new MailAddress(from);
}
public void SendEmail(string to, string subject, string body)
{
// Build the e-mail
var email = new MailMessage
{
Subject = subject,
Body = body,
IsBodyHtml = true,
From = _from
};
email.CC.Add(_from);
_smtpFactory.Invoke(client => client.Send(email));
}
}
ResourceFactory<T>
基本上抽象出Observable.Using
,就像这样:
public class ResourceFactory<T>
where T : IDisposable
{
private readonly Func<T> _factory;
private readonly IScheduler _scheduler;
/// <summary>
/// Create the given resource with a factory that will create instances of the resource.
/// </summary>
/// <param name="factory"></param>
public ResourceFactory(Func<T> factory, IScheduler scheduler)
{
_factory = factory;
_scheduler = scheduler;
}
/// <summary>
/// Invoke the given action by creating a new instance of the resource.
/// </summary>
/// <param name="invocation"></param>
public IObservable<Unit> Invoke(Action<T> invocation)
{
return Observable.Using(_factory, (t) => Observable.Start(() => invocation(t), _scheduler));
}
}
尝试使用StructureMap进行设置时出现问题。首先,StructureMap继续尝试使用带有DotNetEmailProvider
参数的重载from
构造函数。此时我并不关心这一点,所以我进行了一些调查,以了解如何在StructureMap中“选择”构造函数并最终得到此代码:
x.SelectConstructor<DotNetEmailProvider>(() => new DotNetEmailProvider(null));
x.ForConcreteType<DotNetEmailProvider>()
.Configure
.Ctor<ResourceFactory<SmtpClient>>().Is(new ResourceFactory<SmtpClient>(() => new SmtpClient(), TaskPoolScheduler.Default));
x.For<IEmailProvider>()
.Use<DotNetEmailProvider>();
我现在的问题是,现在我收到了这个错误:
{"StructureMap Exception Code: 202\nNo Default Instance defined for PluginFamily System.Reactive.Concurrency.IScheduler, System.Reactive.Interfaces, Version=2.2.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"}
对我来说没有意义,因为,是的,ResourceFactory<T>
构造函数确实将IScheduler
实例作为它的第二个参数,但是我已经通过了在我的配置中(TaskPoolScheduler.Default
),我不一定希望每个IScheduler实例在整个应用程序中都是相同的(所以我不想做x.For<IScheduler>().Is(...)
做什么?
编辑:应该注意我知道我的ResourceFactory<T>.Invoke
方法在订阅观察者之前不会“做”任何事情,但我的问题仍然存在
答案 0 :(得分:0)
当我们要求接口IEmailProvider
时会抛出异常:
var provider = ObjectFactory.GetInstance<IEmailProvider>();
因此,我们应该更准确地配置IEmailProvider
x.For<IEmailProvider>()
.Use<DotNetEmailProvider>()
// plus this
.Ctor<ResourceFactory<SmtpClient>>().Is(new ResourceFactory<SmtpClient>(
() => new SmtpClient(), TaskPoolScheduler.Default));
现在StructureMap
知道足以返回实例化的 IEmailProvider