2010-11-02 32 views
0

在下面的方法中,有很多調用Manager類的case語句(許多已被刪除)。例如,第一個調用ApplicationManager.GetByGUID。任何時候使用「經理」類,都會進行安全檢查。嵌套的try-catches還有更好的方法嗎?

問題:我有可能允許其中一些但不是全部的實體。所以當這個方法運行時,如果其中的一個出來了,它會拋出一個安全異常並且使整個報告崩潰。

有人向我建議,我可以在每個案件的周圍放一個try-catch塊,但是我讀得越多,我越覺得這可能是草率的。我承認並不是很瞭解異常情況......我希望有人能夠提出一種更好的方法來做到這一點......我需要能夠獲得良好的數據,並忽略那些拋出安全異常的數據....或者在這種情況下嘗試捕獲是否可以?

希望是有道理...感謝


private string GetLookup(string value, string type) 
{ 
    MySqlConnection mconn = new MySqlConnection(ConfigurationSettings.AppSettings["UnicornConnectionString_SELECT"]); 

    try 
    { 
     mconn.Open(); 

     lock (reportLookups) 
     { 
      if (reportLookups.ContainsKey(type+value)) 
       return reportLookups[type+value].ToString(); 
      else if (reportLookups.ContainsKey(value)) 
       return reportLookups[value].ToString(); 
      else 
      { 
       switch (type) 
       { 
        case "ATTR_APPLICATIONNAME": 
         if (value != Guid.Empty.ToString()) 
         { 
          reportLookups.Add(type + value, applicationManager.GetByGUID(value).Name); 
         } 
         else 
         { 
          reportLookups.Add(type + value, "Unknown"); 
         } 
         mconn.Close(); 
         return reportLookups[type + value].ToString(); 
         break; 
        case "ATTR_CITYNAME": 
         reportLookups.Add(type + value, UMConstantProvider.UMConstantProvider.GetConstant<UMString64>(int.Parse(value), UMMetricsResourceLibrary.Enumerations.ConstantType.CITY_NAME, ref mconn)); 
         mconn.Close(); 
         return reportLookups[type + value].ToString(); 
         break; 
        case "ATTR_COUNTRYNAME": 
         reportLookups.Add(type + value, UMConstantProvider.UMConstantProvider.GetConstant<UMString2>(int.Parse(value), UMMetricsResourceLibrary.Enumerations.ConstantType.COUNTRY_NAME, ref mconn)); 
         mconn.Close(); 
         return reportLookups[type + value].ToString(); 
         break; 
        case "ATTR_ITEMDURATION": 

         MediaItem mi = mediaItemManager.GetMediaItemByGUID(value); 
         if (mi.MediaItemTypeID == (int)MediaItemType.ExternalVideo || mi.MediaItemTypeID == (int)MediaItemType.ExternalAudio) 
         { 
          reportLookups.Add(type + value, mediaItemManager.GetMediaItemByGUID(value).ExternalDuration); 
          mconn.Close(); 
          return reportLookups[type + value].ToString(); 
         } 
         else 
         { 

          List<BinaryAsset> bins = fileSystemManager.GetBinaryAssetsByMediaItemGuid(value, mi.DraftVersion); 
          var durationasset = from d in bins 
               where d.Duration != 0 
               select d.Duration; 

          if (durationasset.Count() > 0) 
          { 

           reportLookups.Add(type + value, durationasset.ToList()[0]); 

          } 
          else 
          { 
           reportLookups.Add(type + value, 0); 
           mconn.Close(); 
           return reportLookups[type + value].ToString(); 
          } 


         } 

         break; 
       } 
      } 
      return string.Empty; 
     } 
    } 
    finally 
    { 
     mconn.Close(); 
    } 
} 
+5

我認爲這更像是一個代碼重構的例子。你打開'type'參數,這是傳入的 - 爲什麼不分離出不同的方法?將使您的代碼更易讀易維護。另外,你爲什麼要在'case語句*和* finally塊中執行mconn.Close();'只是在最後一次做。 – RPM1984 2010-11-02 22:59:26

+0

+1 @ RPM1984,我同意 – 2010-11-02 23:03:29

+0

哇,這很快,謝謝傢伙 – 2010-11-02 23:14:07

回答

3

作爲一項規則,異常應說明出現了錯誤。如果你通過這種方法的典型運行過程中期待例外,你需要改變你的API,讓你避免異常:

if (mediaItemManager.CanAccessMediaItem(value)) 
{ 
    MediaItem mi = mediaItemManager.GetMediaItemByGUID(value); 
    .... 
} 

這裏是我的一個快速的嘗試重構這段代碼到的東西更合理:

private string GetLookup(string value, string type) 
{ 
    var lookupKey = type + value;       
    using (MySqlConnection mconn = new MySqlConnection(ConfigurationSettings.AppSettings["UnicornConnectionString_SELECT"])) 
    { 
     mconn.Open(); 
     lock (reportLookups) 
     { 
      if (reportLookups.ContainsKey(lookupKey)) 
      { 
       return reportLookups[lookupKey].ToString(); 
      } 
      var value = GetLookupValue(type, value); 
      reportLookups[lookupKey] = value; 
      return value; 
     } 
    } 
} 

private string GetLookupValue(string type, string value) 
{ 
    switch (type) 
    { 
     case "ATTR_APPLICATIONNAME": 
      return value == Guid.Empty.ToString() 
       ? "Unknown" 
       : applicationManager.CanGetByGUID(value) 
        ? applicationManager.GetByGUID(value).Name 
        : string.Empty; 
     case "ATTR_CITYNAME": 
      return UMConstantProvider.UMConstantProvider.GetConstant<UMString64>(int.Parse(value), UMMetricsResourceLibrary.Enumerations.ConstantType.CITY_NAME, ref mconn); 
     case "ATTR_COUNTRYNAME": 
      return UMConstantProvider.UMConstantProvider.GetConstant<UMString2>(int.Parse(value), UMMetricsResourceLibrary.Enumerations.ConstantType.COUNTRY_NAME, ref mconn); 
     case "ATTR_ITEMDURATION": 
      if(mediaItemManager.CanGetMediaItemByGUID(value)) { 
       MediaItem mi = mediaItemManager.GetMediaItemByGUID(value); 
       if (mi.MediaItemTypeID == (int)MediaItemType.ExternalVideo || mi.MediaItemTypeID == (int)MediaItemType.ExternalAudio) 
       { 
        return mediaItemManager.GetMediaItemByGUID(value).ExternalDuration; 
       } 
       else 
       { 
        List<BinaryAsset> bins = fileSystemManager.GetBinaryAssetsByMediaItemGuid(value, mi.DraftVersion); 
        var durationasset = from d in bins 
             where d.Duration != 0 
             select d.Duration; 
        return durationasset.FirstOrDefault() ?? "0"; 
       } 
      } 
      else 
      { 
       return string.Empty; 
      } 
     default: 
      return string.Empty; 
    } 
} 

因爲我不明白這個代碼的全部範圍,我可能過於簡單化它的某些方面,但你可以看到,有一個大量的重構將在這裏完成。將來,您可能需要在http://refactormycode.com/之前運行一些代碼,直到您習慣於使用最佳做法。

+0

雖然通常仍然有必要進行try-catch,以防止檢查和使用之間的有效性發生變化。經典案例是FileNotFound,其中存在一個文件,但在檢查後立即刪除。如果可能的話,最好先檢查一下,或者有一個不會拋出的「嘗試」版本的方法。 – 2010-11-02 23:32:28

+0

@丹·布萊恩特:好點。我特別喜歡'TryGet ...'策略,因爲它避免了競爭條件。在很多情況下,我們仍然需要自問:「如果發生這種情況,會發生什麼?」在這個例子中,如果用戶有權利通過生成報告中途撤銷某個特定類型的對象,我是否還希望他們看到報告的前半部分,其中可能包含其中一些值再允許看到?在這種非常規的情況下,如果報告生成時不時引發異常,我通常會說它不是那麼糟糕。 – StriplingWarrior 2010-11-02 23:44:11

+0

感謝大家的所有評論......我過去潛伏在StackOverflow中尋找答案,但這是我第一次註冊並參與其中。偉大的網站,偉大的思想,...我期待成爲未來更多討論的一部分 – 2010-11-03 15:40:59

0

某處你會喜歡一些代碼:

foreach(Request req in allRequests) 
{ 
    Reply result = MakeReply(req); 
    WriteReply(result); 
} 

把它變成:

foreach(Request req in allRequests) 
{ 
    Reply result; 
    try 
    { 
     result = CreateReply(req); 
    } 
    catch(SecurityException ex) 
    { 
     result = CreateReplyUnauthorized(); 
    } 
    catch(Exception ex) // always the last 
    { 
     LogException(ex); // for bug hunting 

     // Don't show the exception to the user - that's a security risk 
     result = CreateReplySystemError(); 
    } 

    WriteReply(result); 
} 

你可能想要把在try-catch到一個單獨的功能爲您的foreach循環體一旦你捕捉到幾種類型的例外,它就會變得越來越大

StriplingWarrior在他的回覆中也是正確的:「例外情況應該表明出了問題。」讓它們傳播到主循環並在那裏顯示它們。

+0

感謝您的所有評論每個人...我過去潛伏在StackOverflow中尋求答案,但這是我第一次已經註冊並參與其中。偉大的網站,偉大的思想,......我期待着成爲未來更多討論的一部分 – 2010-11-03 15:39:12

相關問題