动态更改函数的调用者

韦斯利·斯凯恩(Wesley Skeen)

我在我的应用程序的DAL中实现了2个提供程序。

一个是Redis Cache提供程序,另一个是数据库提供程序。

public class CacheProvider : IProvider
{
    public List<int> GetCustomerIds()
    {
        return cache.GetCustomerIds();
    }
}

public class DBProvider : IProvider
{
    public List<int> GetCustomerIds()
    {
        return db.GetCustomerIds();
    }
}

我已经为这些实现了一个接口

public interface IProvider
{
     List<int> GetCustomerIds();
}

我有以下情况。

如果高速缓存功能以某种方式失败,或者高速缓存在尝试执行时过期,我想回退并调用该函数的数据库版本。

将实现许多功能,因此我正在考虑创建一个网关,在该网关中所有功能都将作为参数传递,并且如果失败则回退到db版本

public List<int> RunTheMethod(Func<int> myMethodName)
{
    // Run method from cache
    myMethodName()

    if method fails, run method from db
    myMethodName()
}

有没有办法实现这种功能?我知道我可能必须实现其中的一些方法,因为参数会有所不同。

阿兰

尽管我不确定性能,但可以稍加思考使此工作可行

我们有IDataProvider这是由缓存提供者,数据库提供商和“门户”(我已经包含了3种方法中IDataProvider显示不同的回报/参数的例子和重载)实施

网关不必实现IDataProvider,但这样做会使生活变得更轻松,因为网关上的方法需要具有与将在提供程序上调用的方法相同的签名。

网关包含一个IDataProviders列表,对于每个调用,它都会遍历该列表并尝试执行。它返回第一个成功,如果没有成功,则抛出异常。

Execute <>()方法是连接所有内容的快速方法,我们可以每次都调用它,并让它处理与IDataProviders上的方法匹配并在失败时重试。

为了进行测试,我创建了一种方法来强制第一个(缓存提供程序)失败。

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);

    }
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章