【发布时间】:2015-11-03 19:34:17
【问题描述】:
我在这里伤到了我的大脑。
一些背景:
我在多层应用中有多项服务。其中一些是短暂的(应该与using 一起使用),而另一些则不是(所以我只是将它们注入到我想要的任何类中并直接使用)。我的客户端代码有不同的数据接口和随机的using关键字。
出于某些原因(主要是为了科学),我决定对其进行一些重构。我创建了一个通用的 DataServiceAdapter<> 类,对于我使用的每一个服务都应该关闭它,并且这个通用类封装了来自客户端的 using 逻辑。
DataServiceAdapter 看起来像这样(简短的工作示例here on dotnetfiddle)
public class DataServiceAdapter<TService> : IDataService
where TService : IDataService, new()
{
private readonly TService _service;
private readonly Func<Func<TService, dynamic>, dynamic> _run;
public DataServiceAdapter()
{
if (typeof(IDisposable).IsAssignableFrom(typeof(TService)))
{
_run = RunWithUsing;
}
else
{
_service = new TService();
_run = RunWithoutUsing;
}
}
public bool Foo()
{
return _run(x => x.Foo());
}
public int Bar(string arg)
{
return _run(x => x.Bar(arg));
}
private dynamic RunWithUsing(Func<TService, dynamic> func)
{
using (var service = (IDisposable) new TService())
{
return func((TService)service);
}
}
private dynamic RunWithoutUsing(Func<TService, dynamic> func)
{
return func(_service);
}
}
public interface IDataService
{
bool Foo();
int Bar(string arg);
}
客户应该像这样使用它:
//class variable. Get this from IoC container
private readonly IDataService _service;
//somewhere in methods
var resultData = _service.Foo(); //full static type checking
但是因为我的真实生活版本的IDataService 包含几十个方法,所以我像这样重写了DataServiceAdapter(仅更改,dotnetfiddle link):
public class DataServiceAdapter<TService> : IDataServiceAdapter<TService>
where TService : IDataService, new()
{
public dynamic Run(Func<TService, dynamic> func)
{
return _serviceUsing(func);
}
}
public interface IDataServiceAdapter<out TService>
where TService : IDataService
{
dynamic Run(Func<TService, dynamic> func);
}
客户端现在可以通过这种方式使用该版本的DataServiceAdapter:
//class variable. Get this from IoC container
private readonly IDataServiceAdapter<IDataService> _service;
//somewhere in methods
var resultData = _service.Run(s => s.Foo());
由于dynamic,它无需静态检查即可工作
所以(我们接近于质疑)我决定再次重写它(为了科学)并返回静态安全,但无需将所有 IDataService 方法包装在我的适配器类中。
首先我写了这个delegate:
private delegate TRes RunDelegate<TResult>(Func<TService, TResult> func);
但是我不能像上面那样创建这样的委托的变量并传递一些我希望使用的方法。
问题:
有什么方法可以在那里实现我的设计思想(通用服务提供者调用带有using 的方法或没有它的方法并且具有类型安全性)?
【问题讨论】:
标签: c# oop generics dynamic parametric-namespaces