嵌套的尝试捕获还是有更好的方法?

时间:2010-11-02 22:55:07

标签: c# nested try-catch

在下面的方法中,有许多用于调用Manager类的case语句(许多已被删除)。例如,第一个调用ApplicationManager.GetByGUID。每次使用“manager”类时,都会进行安全检查。

问题:我有一些实体可能被允许使用其中一些但不是全部。因此,当这个方法运行时,如果其中一个方法崩溃,它将抛出安全异常并使整个报告崩溃。

有人告诉我,我可以在每个案例周围抛出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();
    }
}

2 个答案:

答案 0 :(得分: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/运行一些代码,直到您习惯使用最佳实践。

答案 1 :(得分: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在他的回复中也是对的:“例外应该表明出了问题。”让它们传播到主循环并在那里显示它们。