小编典典

测试字符串是否是一个没有抛出异常的 guid?

all

我想尝试将字符串转换为 Guid,但我不想依赖捕获异常(

  • 出于性能原因 - 异常是昂贵的
  • 出于可用性原因 - 调试器弹出
  • 出于设计原因 - 预期也不例外

换句话说,代码:

public static Boolean TryStrToGuid(String s, out Guid value)
{
    try
    {
        value = new Guid(s);
        return true;
    }
    catch (FormatException)
    {
        value = Guid.Empty;
        return false;
    }
}

不适合。

我会尝试使用正则表达式,但由于 guid 可以用括号包裹、大括号包裹、不包裹,所以很难。

此外,我认为某些 Guid 值无效(?)


更新 1

有一个好主意,只捕获FormatException,而不是全部。更改了问题的代码示例以包含建议。


更新 2

为什么要担心抛出的异常?我真的经常期待无效的 GUID 吗?

答案是 肯定 的。这就是我使用 TryStrToGuid 的原因 - 我 期待 错误的数据。

示例 1 可以通过将 GUID 附加到文件夹名称来指定命名空间扩展。我可能正在解析文件夹名称,检查最后的 . 是一个 GUID。

c:\Program Files
c:\Program Files.old
c:\Users
c:\Users.old
c:\UserManager.{CE7F5AA5-6832-43FE-BAE1-80D14CD8F666}
c:\Windows
c:\Windows.old

示例 2 我可能正在运行一个频繁使用的 Web 服务器,想要检查一些回发数据的有效性。我不希望无效数据占用比所需资源高 2-3 个数量级的资源。

示例 3 我可能正在解析用户输入的搜索表达式。

在此处输入图像描述

如果他们输入 GUID,我想专门处理它们(例如专门搜索该对象,或在响应文本中突出显示和格式化该特定搜索词。)


更新 3 - 性能基准

测试转换 10,000 个好的 Guid 和 10,000 个坏的 Guid。

Catch FormatException:
   10,000 good:     63,668 ticks
   10,000 bad:   6,435,609 ticks

Regex Pre-Screen with try-catch:
   10,000 good:    637,633 ticks
   10,000 bad:     717,894 ticks

COM Interop CLSIDFromString
   10,000 good:    126,120 ticks
   10,000 bad:      23,134 ticks

ps 我不应该证明一个问题的合理性。


阅读 64

收藏
2022-07-31

共1个答案

小编典典

性能基准

Catch exception:
   10,000 good:    63,668 ticks
   10,000 bad:  6,435,609 ticks

Regex Pre-Screen:
   10,000 good:   637,633 ticks
   10,000 bad:    717,894 ticks

COM Interop CLSIDFromString
   10,000 good:   126,120 ticks
   10,000 bad:     23,134 ticks

COM Intertop(最快)答案:

/// <summary>
/// Attempts to convert a string to a guid.
/// </summary>
/// <param name="s">The string to try to convert</param>
/// <param name="value">Upon return will contain the Guid</param>
/// <returns>Returns true if successful, otherwise false</returns>
public static Boolean TryStrToGuid(String s, out Guid value)
{
   //ClsidFromString returns the empty guid for null strings   
   if ((s == null) || (s == ""))   
   {      
      value = Guid.Empty;      
      return false;   
   }

   int hresult = PInvoke.ObjBase.CLSIDFromString(s, out value);
   if (hresult >= 0)
   {
      return true;
   }
   else
   {
      value = Guid.Empty;
      return false;
   }
}


namespace PInvoke
{
    class ObjBase
    {
        /// <summary>
        /// This function converts a string generated by the StringFromCLSID function back into the original class identifier.
        /// </summary>
        /// <param name="sz">String that represents the class identifier</param>
        /// <param name="clsid">On return will contain the class identifier</param>
        /// <returns>
        /// Positive or zero if class identifier was obtained successfully
        /// Negative if the call failed
        /// </returns>
        [DllImport("ole32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, PreserveSig = true)]
        public static extern int CLSIDFromString(string sz, out Guid clsid);
    }
}

底线:如果您需要检查字符串是否为 guid,并且您关心性能,请使用 COM Interop。

如果您需要将字符串表示形式的 guid 转换为 Guid,请使用

new Guid(someString);
2022-07-31