Ian*_*oyd 180 c# string parsing guid
我想尝试将字符串转换为Guid,但我不想依赖捕获异常(
换句话说代码:
public static Boolean TryStrToGuid(String s, out Guid value)
{
try
{
value = new Guid(s);
return true;
}
catch (FormatException)
{
value = Guid.Empty;
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
不适合.
我会尝试使用RegEx,但由于guid可以括号括起来,括号包裹,没有包装,使其变得困难.
另外,我认为某些Guid值无效(?)
更新1
ChristianK有一个好主意只能抓住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
Run Code Online (Sandbox Code Playgroud)
示例2我可能正在运行一个使用频繁的Web服务器,想要检查一些发布的数据的有效性.我不希望无效数据占用比需要高2-3个数量级的资源.
示例3我可能正在解析用户输入的搜索表达式.

如果他们输入GUID,我想特别处理它们(例如专门搜索该对象,或在响应文本中突出显示并格式化该特定搜索词.)
更新3 - 性能基准
测试转换10,000个好Guids和10,000个坏Guids.
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
Run Code Online (Sandbox Code Playgroud)
ps我不应该为一个问题辩护.
Ian*_*oyd 107
绩效基准
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
Run Code Online (Sandbox Code Playgroud)
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);
}
}
Run Code Online (Sandbox Code Playgroud)
结论:如果您需要检查字符串是否为guid,并且您关心性能,请使用COM Interop.
如果需要将String表示中的guid转换为Guid,请使用
new Guid(someString);
Run Code Online (Sandbox Code Playgroud)
No *_*rns 89
一旦.net 4.0可用,您就可以使用Guid.TryParse().
Ant*_*nes 66
你不会喜欢这个,但是什么让你觉得捕捉异常会变慢?
与成功的算法相比,您期望解析GUID的失败尝试次数是多少?
我的建议是使用您刚刚创建的功能并分析您的代码.如果你发现这个函数确实是一个热点,那么就修复它,但不是之前.
小智 39
在.NET 4.0中,您可以编写如下:
public static bool IsValidGuid(string str)
{
Guid guid;
return Guid.TryParse(str, out guid);
}
Run Code Online (Sandbox Code Playgroud)
Chr*_*n.K 21
我至少会把它重写为:
try
{
value = new Guid(s);
return true;
}
catch (FormatException)
{
value = Guid.Empty;
return false;
}
Run Code Online (Sandbox Code Playgroud)
你不想在SEHException,ThreadAbortException或其他致命或非相关的东西上说"无效的GUID".
更新:从.NET 4.0开始,Guid有一组新的方法:
真的,应该使用那些(如果仅仅是因为它们不是在内部使用try-catch"天真地"实现的).
Mar*_*ett 13
Interop比捕获异常慢得多:
在快乐的道路上,拥有10,000个Guids:
Exception: 26ms
Interop: 1,201ms
Run Code Online (Sandbox Code Playgroud)
在不愉快的道路上:
Exception: 1,150ms
Interop: 1,201ms
Run Code Online (Sandbox Code Playgroud)
它更加一致,但也一直较慢.在我看来,配置调试器只会打破未处理的异常会更好.
好吧,这是你需要的正则表达式......
^[A-Fa-f0-9]{32}$|^({|\\()?[A-Fa-f0-9]{8}-([A-Fa-f0-9]{4}-){3}[A-Fa-f0-9]{12}(}|\\))?$|^({)?[0xA-Fa-f0-9]{3,10}(, {0,1}[0xA-Fa-f0-9]{3,6}){2}, {0,1}({)([0xA-Fa-f0-9]{3,4}, {0,1}){7}[0xA-Fa-f0-9]{3,4}(}})$
Run Code Online (Sandbox Code Playgroud)
但这仅适用于初学者.您还必须验证日期/时间等各个部分是否在可接受的范围内.我无法想象这比你已经概述的try/catch方法更快.希望您没有收到那么多无效的GUID来保证这种类型的支票!
虽然使用错误确实成本更高,但大多数人认为他们的大部分 GUID 将由计算机生成,因此 a 并TRY-CATCH不太昂贵,因为它只在CATCH. 您可以通过对两者进行简单测试(用户 public,无密码)来向自己证明这一点。
干得好:
using System.Text.RegularExpressions;
/// <summary>
/// Validate that a string is a valid GUID
/// </summary>
/// <param name="GUIDCheck"></param>
/// <returns></returns>
private bool IsValidGUID(string GUIDCheck)
{
if (!string.IsNullOrEmpty(GUIDCheck))
{
return new Regex(@"^(\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\}{0,1})$").IsMatch(GUIDCheck);
}
return false;
}
Run Code Online (Sandbox Code Playgroud)
出于可用性原因 - 弹出调试器
如果您要使用try/catch方法,可以添加[System.Diagnostics.DebuggerHidden]属性,以确保调试器不会中断,即使您已将其设置为中断.
我也遇到过类似的情况,我注意到无效字符串的长度几乎从来不是 36 个字符。因此,基于这一事实,我对您的代码进行了一些更改,以获得更好的性能,同时仍然保持简单。
public static Boolean TryStrToGuid(String s, out Guid value)
{
// this is before the overhead of setting up the try/catch block.
if(value == null || value.Length != 36)
{
value = Guid.Empty;
return false;
}
try
{
value = new Guid(s);
return true;
}
catch (FormatException)
{
value = Guid.Empty;
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
71023 次 |
| 最近记录: |