2015-04-06 58 views
1

好了,以示我的代碼看起來像(這一點也適用,但不一定漂亮):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語句如下?

+0

你可能會考慮在'params'關鍵字,但我不知道你想什麼是可能的。 – vesan

+0

不幸的是,C#沒有使這個更好的類型安全的機制。它沒有可變的泛型,代表沒有共同的接口,你只需要求助於這樣的解決方案或犧牲類型安全性,並使用反射或建立動態表達式。 –

+0

我不認爲有任何合理的方法來做到這一點。雖然我覺得它有點令人困惑,但可能要稍微改寫一下你的問題。我可以發表一個集中這種邏輯的想法,但這是一種解決方法。這個概念是爲每個可能的arg創建一個字段的類型,使用靜態初始化器來實例化它,然後在你調用的類型上有一個'Query'方法,並且它具有所有的if/else邏輯來選擇哪個方法基於它的屬性的無效性來調用。我會說這與理想情況很不相稱,但我不知道你會如何獲得這種靈活性。 – evanmcdonnal

回答

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

我不明白你的代碼。方法有一個ref參數*和*返回一個值。所以doMethod應該像response = doMethod(ref @out); – a11smiles

+0

也可以。它並不重要,但你應該能夠動態地將需要調用的方法傳遞給可以傳遞給Logic()的包裝器Func。這種方式可以通過Logic()中傳遞的Func調用。如果你提供了更多的代碼,我可以想出更好的答案。 – ohmusama

+0

問題是,您假定所有三種Query方法都調用一個稱爲*'方法'的方法的重載版本。事實並非如此。我需要將方法及其參數傳遞給Query方法。這就是爲什麼我在我的查詢方法中使用Func <>參數。 – a11smiles

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作爲參數,因爲它會始終以同一個列表和相同數量的參數。 if (typeof(in1[0]) == T1) { ... }

0

感謝@ohmusama:

然後你會通過檢查in1.Count和各個項目的類型,執行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; 
     } 
    }