带有重载方法的C#函数

时间:2015-04-06 23:08:28

标签: c#

好的,要显示我的代码看起来像什么(这可行,但不一定很漂亮):

    public delegate Response Func<R1>(ref R1 out1);
    public delegate Response Func<T1, R1>(T1 in1, ref R1 out1);
    public delegate Response Func<T1, T2, R1>(T1 in1, T2 in2, ref R1 out1);
    public delegate Response Func<T1, T2, T3, R1>(T1 in1, T2 in2, T3 in3, ref R1 out1);
    public delegate Response Func<T1, T2, T3, T4, R1>(T1 in1, T2 in2, T3 in3, T4 in4, ref R1 out1);
    public delegate Response Func<T1, T2, T3, T4, T5, R1>(T1 in1, T2 in2, T3 in3, T4 in4, T5 in5, ref R1 out1);
    public delegate Response Func<T1, T2, T3, T4, T5, T6, R1>(T1 in1, T2 in2, T3 in3, T4 in4, T5 in5, T6 in6, ref R1 out1);


    public static Response Query<R1>(Func<R1> method, ref R1 out1)
    {
        return QueryAll<object, object, object, object, object, object, R1>(method, null, null, null, null, null, null, ref out1);
    }

    public static Response Query<T1, R1>(Func<T1, R1> method, T1 in1, ref R1 out1)
    {
        return QueryAll<T1, object, object, object, object, object, R1>(method, in1, null, null, null, null, null, ref out1);
    }

    public static Response Query<T1, T2, R1>(Func<T1, T2, R1> method, T1 in1, T2 in2, ref R1 out1)
    {
        return QueryAll<T1, T2, object, object, object, object, R1>(method, in1, in2, null, null, null, null, ref out1);
    }

    public static Response Query<T1, T2, T3, R1>(Func<T1, T2, T3, R1> method, T1 in1, T2 in2, T3 in3, ref R1 out1)
    {
        return QueryAll<T1, T2, T3, object, object, object, R1>(method, in1, in2, in3, null, null, null, ref out1);
    }

    public static Response Query<T1, T2, T3, T4, R1>(Func<T1, T2, T3, T4, R1> method, T1 in1, T2 in2, T3 in3, T4 in4, ref R1 out1)
    {
        return QueryAll<T1, T2, T3, T4, object, object, R1>(method, in1, in2, in3, in4, null, null, ref out1);
    }

    public static Response Query<T1, T2, T3, T4, T5, R1>(Func<T1, T2, T3, T4, T5, R1> method, T1 in1, T2 in2, T3 in3, T4 in4, T5 in5, ref R1 out1)
    {
        return QueryAll<T1, T2, T3, T4, T5, object, R1>(method, in1, in2, in3, in4, in5, null, ref out1);
    }

    public static Response Query<T1, T2, T3, T4, T5, T6, R1>(Func<T1, T2, T3, T4, T5, T6, R1> method, T1 in1, T2 in2, T3 in3, T4 in4, T5 in5, T6 in6, ref R1 out1)
    {
        return QueryAll<T1, T2, T3, T4, T5, T6, R1>(method, in1, in2, in3, in4, in5, in6, ref out1);
    }

    private static Response QueryAll<T1, T2, T3, T4, T5, T6, R1>(Delegate method, T1 in1, T2 in2, T3 in3, T4 in4, T5 in5, T6 in6, ref R1 out1)
    {
        try
        {
            Response response = null;

            // Test if the method's class implements ICacheable
            if (method.GetType() is ICacheable)
            {
                // Try to get the value from the cache if available
                out1 = ((ICacheable)method.Target).Get<R1>(out1);

                // If not null, return the value and exit
                if (out1 != null)
                    return null;
                else
                {
                    // Value is null, but should be cached, so attempt to load to cache and return it
                    if (in6 != null)
                        response = ((Func<T1, T2, T3, T4, T5, T6, R1>)method)(in1, in2, in3, in4, in5, in6, ref out1);
                    else if (in5 != null)
                        response = ((Func<T1, T2, T3, T4, T5, R1>)method)(in1, in2, in3, in4, in5, ref out1);
                    else if (in4 != null)
                        response = ((Func<T1, T2, T3, T4, R1>)method)(in1, in2, in3, in4, ref out1);
                    else if (in3 != null)
                        response = ((Func<T1, T2, T3, R1>)method)(in1, in2, in3, ref out1);
                    else if (in2 != null)
                        response = ((Func<T1, T2, R1>)method)(in1, in2, ref out1);
                    else if (in1 != null)
                        response = ((Func<T1, R1>)method)(in1, ref out1);
                    else
                        response = ((Func<R1>)method)(ref out1);

                    // If value from database is not null, save it in cache
                    if (out1 != null)
                        ((ICacheable)method.Target).Set<R1>(out1);

                    return response;
                }
            }
            else
            {
                // Get data from database
                if (in6 != null)
                    response = ((Func<T1, T2, T3, T4, T5, T6, R1>)method)(in1, in2, in3, in4, in5, in6, ref out1);
                else if (in5 != null)
                    response = ((Func<T1, T2, T3, T4, T5, R1>)method)(in1, in2, in3, in4, in5, ref out1);
                else if (in4 != null)
                    response = ((Func<T1, T2, T3, T4, R1>)method)(in1, in2, in3, in4, ref out1);
                else if (in3 != null)
                    response = ((Func<T1, T2, T3, R1>)method)(in1, in2, in3, ref out1);
                else if (in2 != null)
                    response = ((Func<T1, T2, R1>)method)(in1, in2, ref out1);
                else if (in1 != null)
                    response = ((Func<T1, R1>)method)(in1, ref out1);
                else
                    response = ((Func<R1>)method)(ref out1);

                return response;
            }
        }
        catch (Exception exc)
        {
            CustomException exception = exc.ToCustomException();
            exception.Code = ResponseCodes.UnknownError;
            throw exception;
        }
    }

这是数据抽象层。同样,我的问题是我想允许开发人员传递方法和最多6个参数。但是,我只想要一个主要方法来包含我的所有逻辑,以便更容易维护。然后,根据某些条件(是否为缓存中的对象),调用数据层上的方法从存储库中读取对象,存储在缓存中,然后将对象返回给控制器。

有比下面的多个if / else语句更好的方法吗?

3 个答案:

答案 0 :(得分:2)

您可以将您的业务逻辑包含在另一个方法中,该方法具有您要调用的方法的参数

public static Response Query<R1>(Func<Tuple<Result, R1>> method, ref R1 @out)
{
    Tuple<Result, R1> result = Logic(() => method());
    @out = result.Item2;
    return result.Item1;
}

public static Response Query<T1, R1>(Func<T1, Tuple<Result, R1>> method, T1 a, ref R1 @out)
{
    Tuple<Result, R1> result = Logic(() => method(a));
    @out = result.Item2;
    return result.Item1;
}

public static Response Query<T1, T2, R1>(Func<T1, T2, Tuple<Result, R1>> method, T1 a, T2 b, ref R1 @out)
{
    Tuple<Result, R1> result = Logic(() => method(a, b));
    @out = result.Item2;
    return result.Item1;
}

...

public static Tuple<Result, R1> Logic<R1>(Func<Tuple<Result, R1>> doMethod)
{
    Tuple<Result, R1> result;
    // logic
    if(true) { result = doMethod(); }
    ...

    // watch out if this doesn't get assigned, can cause problems downstream
    return result;
}

答案 1 :(得分:0)

如果将T1,T2和其他参数作为单独的参数放入列表中会怎样? List<object>

你会得到类似的东西:

public static Response Query<L1,R1>(L1 in1, ref R1 out1)
{
    // The SAME business logic with the same if/then statements
    if (true)
        out1 = method(in1, in2);
    else
        // Some other business logic
}

没有必要将method作为参数传递,因为它总是采用相同的列表和相同数量的参数。

然后,您可以通过检查method以及每个项目的类型,在in1.Count中执行相同的操作:if (typeof(in1[0]) == T1) { ... }

答案 2 :(得分:0)

谢谢@ohmusama!我稍微调整了你的代码,因为我还需要在我的通用查询方法中使用返回的引用参数,但是你帮了很多!

以下是一个重载方法的最终答案:

    public static Response Query<T1, T2, T3, T4, T5, T6, R1>(Func<T1, T2, T3, T4, T5, T6, Tuple<Response, R1>> method, T1 in1, T2 in2, T3 in3, T4 in4, T5 in5, T6 in6, ref R1 out1)
    {
        return QueryAll(() => method(in1, in2, in3, in4, in5, in6), ref out1);
    }

    private static Response QueryAll<R1>(Func<Tuple<Response, R1>> method, ref R1 out1)
    {
        try
        {
            Tuple<Response, R1> result;

            // Test if the method's class implements ICacheable
            if (method.GetType() is ICacheable)
            {
                // Try to get the value from the cache if available
                out1 = ((ICacheable)method.Target).Get<R1>(out1);

                // If not null, return the value and exit
                if (out1 != null)
                    return null;
                else
                {
                    // Value is null, but should be cached, so attempt to load to cache and return it
                    result = method();
                    out1 = result.Item2;

                    // If value from database is not null, save it in cache
                    if (out1 != null)
                        ((ICacheable)method.Target).Set<R1>(out1);

                    return result.Item1;
                }
            }
            else
            {
                // Get data from database
                result = method();
                out1 = result.Item2;

                return result.Item1;
            }
        }
        catch (Exception exc)
        {
            CustomException exception = exc.ToCustomException();
            exception.Code = ResponseCodes.UnknownError;
            throw exception;
        }
    }