C# 动态更改函数的调用方
我已经在我的应用程序的DAL中实现了2个提供者 一个是Redis缓存提供程序,另一个是数据库提供程序C# 动态更改函数的调用方,c#,.net,caching,C#,.net,Caching,我已经在我的应用程序的DAL中实现了2个提供者 一个是Redis缓存提供程序,另一个是数据库提供程序 public class CacheProvider : IProvider { public List<int> GetCustomerIds() { return cache.GetCustomerIds(); } } public class DBProvider : IProvider { public List<int
public class CacheProvider : IProvider
{
public List<int> GetCustomerIds()
{
return cache.GetCustomerIds();
}
}
public class DBProvider : IProvider
{
public List<int> GetCustomerIds()
{
return db.GetCustomerIds();
}
}
公共类缓存提供程序:IProvider
{
公共列表getCustomerId()
{
返回cache.getCustomerId();
}
}
公共类DBProvider:IProvider
{
公共列表getCustomerId()
{
返回db.getCustomerId();
}
}
我已经为这些实现了一个接口
public interface IProvider
{
List<int> GetCustomerIds();
}
公共接口IProvider
{
列出getCustomerID();
}
我有以下情况
如果缓存函数在尝试执行时以某种方式出现故障或缓存过期,我希望后退并调用该函数的db版本
将实现许多函数,因此我考虑创建一个网关,其中所有函数都将作为参数传递,如果失败,则返回到db版本
public List<int> RunTheMethod(Func<int> myMethodName)
{
// Run method from cache
myMethodName()
if method fails, run method from db
myMethodName()
}
公共列表运行方法(Func myMethodName)
{
//从缓存运行方法
myMethodName()
若方法失败,则从db运行方法
myMethodName()
}
有没有办法实现这种功能?我知道我可能必须实现其中的一些方法,因为参数会有所不同。虽然我不确定性能,但通过一些思考,这是可能的 我们有IDataProvider,它由缓存提供程序、数据库提供程序和“网关”实现(我在IDataProvider中包含了3个方法,以显示不同返回/参数和重载的示例) 网关不必实现IDataProvider,但这样做会使工作更轻松,因为网关上的方法需要具有与提供者上要调用的方法相同的签名 网关包含一个IDataProviders列表,对于每个调用,它都会遍历该列表并尝试执行。它返回第一次成功,如果没有成功,则抛出异常 Execute()方法是一种快速连接一切的方法,我们可以每次调用它,让它处理与IDataProviders上的方法的匹配,然后在失败时重新尝试 出于测试目的,我创建了一种强制第一个(缓存提供程序)失败的方法
你基本上回答了你自己的问题!通常我会在我的客户端/前端之间有一个服务层,这将检查对象或对象集合是否在缓存中,如果不在缓存中,我将从db获取并填充缓存。你说的失败是什么意思?失败是指如果缓存出现故障或遇到错误。非常感谢你的回答,艾伦,我会在当天结束之前实施,我会回复你的
interface IDataProvider {
List<int> Method1();
List<string> Method2(string parameter1);
List<string> Method2(string parameter1, string parameter2);
}
class DataProvider1 : IDataProvider {
private readonly string[] Strings = { "A", "B", "C" };
private bool _callFails;
public DataProvider1(bool callFails) {
_callFails = callFails;
}
public List<int> Method1() {
if (_callFails) {
throw new Exception();
}
return new List<int>(){1,2,3};
}
public List<string> Method2(string parameter1) {
if (_callFails) {
throw new Exception();
}
return Strings.Select(s => s + parameter1).ToList();
}
public List<string> Method2(string parameter1, string parameter2) {
if (_callFails) {
throw new Exception();
}
return Strings.Select(s => s + parameter1 + parameter2).ToList();
}
}
class DataProvider2 : IDataProvider {
private readonly string[] Strings = { "D", "E", "F" };
public List<int> Method1() {
return new List<int>(){4,5,6};
}
public List<string> Method2(string parameter1) {
return Strings.Select(s => s + parameter1).ToList();
}
// overload
public List<string> Method2(string parameter1, string parameter2) {
return Strings.Select(s => s + parameter1 + parameter2).ToList();
}
}
class Gateway : IDataProvider {
private readonly List<IDataProvider> _dataProviders;
public Gateway(IEnumerable<IDataProvider> dataProviders) {
_dataProviders = new List<IDataProvider>(dataProviders);
}
public List<int> Method1() {
return Execute<List<int>>();
}
public List<string> Method2(string parameter1) {
return Execute<List<string>>(parameter1);
}
public List<string> Method2(string parameter1, string parameter2) {
return Execute<List<string>>(parameter1, parameter2);
}
private T Execute<T>(params object[] parameters) {
StackTrace stackTrace = new StackTrace();
MethodBase methodBase = stackTrace.GetFrame(1).GetMethod();
var methodInfo = typeof(IDataProvider).GetMethod(methodBase.Name, methodBase.GetParameters().Select(p => p.ParameterType).ToArray());
var index = 0;
while (index < _dataProviders.Count) {
try {
return(T)methodInfo.Invoke(_dataProviders[index], parameters);
} catch (Exception) {
index++;
}
}
throw new Exception("None of the methods succeeded");
}
}
[TestClass]
public class DataProviderFixture {
#region Create
private Gateway Create(bool firstCallFails = false) {
return new Gateway(new IDataProvider []{
new DataProvider1(firstCallFails),
new DataProvider2()});
}
#endregion
[TestMethod]
public void ExecuteNoProblems() {
var gateway = Create();
var numbers = gateway.Method1();
CollectionAssert.AreEqual(new[] { 1, 2, 3 }, numbers);
var letters = gateway.Method2("1");
CollectionAssert.AreEqual(new[] { "A1", "B1", "C1" }, letters);
letters = gateway.Method2("1", "a");
CollectionAssert.AreEqual(new[] { "A1a", "B1a", "C1a" }, letters);
}
[TestMethod]
public void ExecuteFirstCallFails() {
var gateway = Create(true);
var numbers = gateway.Method1();
CollectionAssert.AreEqual(new[] { 4, 5, 6 }, numbers);
var letters = gateway.Method2("2");
CollectionAssert.AreEqual(new[] { "D2", "E2", "F2" }, letters);
letters = gateway.Method2("1", "b");
CollectionAssert.AreEqual(new[] { "D1b", "E1b", "F1b" }, letters);
}
}