3 回答
TA贡献1946条经验 获得超4个赞
同意 Jogge 的观点,迭代IFileBackups 会是一个更好的选择,但是为每种类型创建一个接口是不行的。相反,您可以添加一个提供IEnumerable<IFileBackup>(聚合)的类。例如:
public class BackupBundle : IEnumerable<IFileBackup>
{
private readonly List<IFileBackup> _backups = new List<IFileBackup>();
// default constructor creates default implementations
public BackupBundle()
: this(new List<IFileBackup> {new BackUpMechanismA(), new BackUpMechanismB()}) {}
// allow users to add custom backups
public BackupBundle(IEnumerable<IFileBackup> backups)
{
foreach (var backup in backups)
Add(backup);
}
public void Add(IFileBackup backup)
{
if (backup == null) throw new ArgumentNullException(nameof(backup));
_backups.Add(backup);
}
public IEnumerator<IFileBackup> GetEnumerator()
{
foreach (var backup in _backups)
yield return backup;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public class Caller
{
private readonly IEnumerable<IFileBackup> _backups;
public Caller(IEnumerable<IFileBackup> backups)
{
_backups = backups ?? throw new ArgumentNullException(nameof(backups));
}
public async Task BackupFile(byte[] file)
{
foreach (var b in _backups)
{
try
{
await b.Backup(file);
break;
}
catch (Exception e) { }
}
}
}
注册可按以下方式进行:
builder.RegisterInstance(new BackupBundle()).As<IEnumerable<IFileBackup>>();
builder.RegisterType<Caller>();
它允许您按类名解析:
var caller = scope.Resolve<Caller>();
如您所见,BackupBundle具有BackUpMechanismA和的依赖关系BackUpMechanismB。您可以通过引入另一层抽象来摆脱它,但我不想这样做。我主要关心的是使Caller更健壮。您可能想要引入重试逻辑、超时等。
TA贡献2036条经验 获得超8个赞
为了使您的设计工作,您可以尝试下一种方法:
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<BackUpMechanismA>().Keyed<IFileBackup>("A");
builder.RegisterType<BackUpMechanismB>().Keyed<IFileBackup>("B");
builder.RegisterType<Caller>()
.WithParameter((p, ctx) => p.Position == 0, (p, ctx) => ctx.ResolveKeyed<IFileBackup>("A"))
.WithParameter((p, ctx) => p.Position == 1, (p, ctx) => ctx.ResolveKeyed<IFileBackup>("B"));
IContainer container = builder.Build();
var caller = container.Resolve<Caller>();
Console.ReadKey();
}
但是在我看来,您可能在这里不需要这样的多态性。实现这样的东西会更加明显和描述性:
public async Task BackupFile(byte[] file)
{
try
{
await BackUpToAmazonS3(file);
}
catch (AmazonS3LoadingException)
{
await BackUpToLocalDisk(file);
}
}
在这个例子中,很明显发生了什么。在那里BackUpToAmazonS3你可以使用一些注入AmazonS3FileBackUp和BackUpToLocalDisk使用中的LocalDiskFileBackUp东西。关键是当您不打算更改实现时,您不需要多态性。在您的上下文中应该清楚吗?您尝试将备份放入某个远程存储,然后,如果失败,则放入本地磁盘。您无需在此处隐藏含义。这是你的逻辑,应该很清楚,当你阅读代码时,我想。希望能帮助到你。
TA贡献1815条经验 获得超6个赞
尝试使用名称注册,然后使用名称解析:
builder.RegisterType<BackupMechanismA>().Named<IFileBackup>("BackUpMechanismA");
builder.RegisterType<BackupMechanismB>().Named<IFileBackUp>("BackUpMechanismB");
_backupA = container.ResolveNamed<IFileBackUp>
("BackUpMechanismA");
_backupB = container.ResolveNamed<IFileBackUp>
("BackUpMechanismB");
在运行时解析实例,而不是通过构造函数注入。这将让您根据需要解析为相应的类型。让我知道这个是否奏效。
- 3 回答
- 0 关注
- 178 浏览
添加回答
举报