简体   繁体   English

具有重载方法的C#函数

[英]C# Functions With Overloaded Methods

Okay, to show what my code looks like (and this works, but isn't necessarily pretty): 好的,显示我的代码是什么样的(虽然可以,但是不一定很漂亮):

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

This is the data abstraction layer. 这是数据抽象层。 Again, my question is I want to allow a developer to pass in a method and up to 6 parameters. 同样,我的问题是我想允许开发人员传入一个方法和最多6个参数。 But, I only want one main method to contain all of my logic so that it's easier to maintain. 但是,我只希望一个主要方法包含我所有的逻辑,以便于维护。 Then, based on certain conditions (is the object in cache or not), call a method on the data layer to read in the object from the repository, store in cache, then return object to the controller. 然后,根据某些条件(对象是否在缓存中),在数据层上调用一个方法以从存储库中读取对象,存储在缓存中,然后将对象返回给控制器。

Is there a better way to do this than multiple if/else statements like below? 是否有比下面的多个if / else语句更好的方法?

You could have your business logic contained in another method, that has an argument for the method you want to call 您可以将业务逻辑包含在另一个方法中,该方法具有要调用的方法的参数

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

What if instead putting T1, T2, and the others as separate parameters you would put them in a list? 如果将T1,T2和其他参数作为单独的参数放置在列表中怎么办? List<object>

You would get something similar to this: 您将获得与此类似的内容:

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
}

There would be no need to pass method as a parameter as it would always take the same list and the same number of parameters. 无需将method作为参数传递,因为它将始终使用相同的列表和相同数量的参数。

Then you'd perform the same operations in method by checking in1.Count and the type of each individual item: if (typeof(in1[0]) == T1) { ... } 然后,您将通过检查in1.Count和每个单独项的类型在method执行相同的操作: if (typeof(in1[0]) == T1) { ... }

Thanks @ohmusama! 谢谢@ohmusama! I tweaked your code a bit because I needed to still use the returned reference parameter in my Generic query method, but you helped a ton! 我稍微调整了一下代码,因为我仍然需要在通用查询方法中使用返回的引用参数,但是您帮了很多忙!

Below is my final answer with one overloaded method: 以下是我对一种重载方法的最终回答:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM