题
我想转换一串Guid,但我不希望依赖捕的例外情况(
- 对于业绩原因的例外情况是昂贵的
- 为实用性的原因-调试器弹出
- 设计原因预期的不是特殊的
换句话说代码:
public static Boolean TryStrToGuid(String s, out Guid value)
{
try
{
value = new Guid(s);
return true;
}
catch (FormatException)
{
value = Guid.Empty;
return false;
}
}
是不合适的。
我将尝试使用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
例2 我可能是运行一个大量使用网络服务器想要检查有效性的一些发回的数据。我不想无效的数据占用的资源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
p.s.我不应该来证明一个问题。
解决方案
业绩基准
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互操作。
如果需要转换guid在串表示Guid,使用
new Guid(someString);
其他提示
一次。净4.0是可你可以使用 Guid.TryParse()
.
你不会喜欢这个但是什么使你认为醒目的例外是要慢?
如何许多次失败的尝试来分析GUID是你期待着在比较成功的人吗?
我的建议是,使用该功能你们只是创造和分析代码。如果你发现,这个功能是真正热点 然后 修复它,而不是之前。
中。净4.0你可以写如下:
public static bool IsValidGuid(string str)
{
Guid guid;
return Guid.TryParse(str, out guid);
}
我至少可以改写为:
try
{
value = new Guid(s);
return true;
}
catch (FormatException)
{
value = Guid.Empty;
return false;
}
你不想说的"无效GUID"在SEHException,ThreadAbortException或其他致命的或者非相关的东西。
更新:开始与。净4.0,有一套新的方法可用于Guid:
真的,那些应当使用的(如果只有一个事实,即他们不是"天真"实现使用的尝试追赶的境内).
互操作慢于刚醒目的例外:
在快乐的道路,与10 000名Guid:
Exception: 26ms
Interop: 1,201ms
在不愉快的路径:
Exception: 1,150ms
Interop: 1,201ms
这是更一致的,但它也一直较为缓慢。在我看来你会更好的配置调试器,只有打破关于未经处理的例外情况。
嗯,这里是regex你需要...
^[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}(}})$
但这只是开始。你也会有确认的各部分,例如日期/时间是在可接受范围。我不能想象一下,这是任何速度比试图/抓的方法,你已经概述。希望你不是接受,许多无效Guid,以保证这种类型的检查!
为实用性的原因-调试器弹出
如果你去尝试/抓的方法可以添加的[体系。诊断。DebuggerHidden]属性,以确保调试器不会破坏甚至如果你设置,它打破。
虽然它 是 真的,使用错误是更昂贵,大多数人认为,他们大多数的Guid是将计算机产生的这样一个 TRY-CATCH
是不是过于昂贵,因为它只能产生成本上 CATCH
.你可以证明这一点给自己一个简单的测试 两个 (用户公开,没有密码)。
在这里,你去:
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;
}
我有一个类似的情况,我注意到,几乎永远是无效的串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;
}
}
据我所知,没有东西像Guid。TryParse在mscrolib.根据参考源,Guid类型的大型复杂的构造,检查所有种类的guid格式,并试图分析。没有辅助方法你可以打电话,甚至通过的反映。我认为你必须要寻找3方Guid的分析程序,或写你自己。
运行的潜在GUID虽然RegEx或一些自定义的代码完整性检查,以确保strig至少看起来像一个GUID并且只由有效字(也许,它似乎适合的总体格式)。如果它不能通过检查返回的一个错误-这可能会淘汰绝大多数无效串。
然后把串如你所述,仍然醒目的例外情况的几串无效的,获得通过的精神健康检查。
Jon双向飞碟有没有一个分析对于类似的东西对于分析整数(前TryParse是在该框架): 检查,如果一串可以转换为Int32
然而,作为 AnthonyWJones 表示你可能不应该担心这个。
bool IsProbablyGuid(string s)
{
int hexchars = 0;
foreach(character c in string s)
{
if(IsValidHexChar(c))
hexchars++;
}
return hexchars==32;
}
- 得到的反射器
- 复制恩和粘贴Guid。构造函数(String)
- 取代每次数的"扔新的..."与"return false"。
Guid的构造函数是相当多的汇编regex,这样你会得到完全相同的行为没有开销的例外。
- 这不会构成一个反向工程?我认为它这么做,并作为这样可能是非法的。
- 将打破,如果GUID形式的变化。
更酷的解决办法是动态文书的方法,通过替换"扔新"的飞行。
我投票的GuidTryParse的链接,公布上通过 乔恩 或类似的解决方案(IsProbablyGuid).我会写的一样那些对我转化的图书馆。
我认为这完全是跛脚的,这个问题是如此复杂的。"是"或者"作为"的关键词将只是罚款,如果一个Guid可能是空。但由于某些原因,尽管SQL服务器的"确定"这.净是没有的。为什么?有什么价值的Guid。空的吗?这只是一个愚蠢的问题创造了通过设计的。净的,它真的错误我的时候对公约的一种语言上的步骤本身。最佳的答案迄今已使用COM互操作,因为该框架不能处理它的优雅?"可以这一串是一个GUID?"应该是一个问题是容易回答。
依靠的例外时被抛是确定的,直到应用程序在互联网上。在这一点上我只是给自己设定了一个拒绝服务攻击。甚至如果我没有得到"攻击",我知道一些雅虎是会猴子的网址,或者也许我的营销部门将发出一个错误格式的链接,然后我应用程序已经遭受相当沉重性的打击,这可能带来的服务器,因为我没有写我的代码处理的问题,即不应该发生,但我们都知道将会发生。
这个模糊的行一个位于"例外"-但底线,甚至如果问题是罕见的,如果它能发生足够的时间在一个短短的时间跨度应用程序提供服务的渔获量从这一切,然后我想投掷一个例外是不好的形式。
TheRage3K
如果类型的ctype(myvar:对象)是Guid那么。。...
Private Function IsGuidWithOptionalBraces(ByRef strValue As String) As Boolean
If String.IsNullOrEmpty(strValue) Then
Return False
End If
Return System.Text.RegularExpressions.Regex.IsMatch(strValue, "^[\{]?[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}[\}]?$", System.Text.RegularExpressions.RegexOptions.IgnoreCase)
End Function
Private Function IsGuidWithoutBraces(ByRef strValue As String) As Boolean
If String.IsNullOrEmpty(strValue) Then
Return False
End If
Return System.Text.RegularExpressions.Regex.IsMatch(strValue, "^[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}$", System.Text.RegularExpressions.RegexOptions.IgnoreCase)
End Function
Private Function IsGuidWithBraces(ByRef strValue As String) As Boolean
If String.IsNullOrEmpty(strValue) Then
Return False
End If
Return System.Text.RegularExpressions.Regex.IsMatch(strValue, "^\{[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}\}$", System.Text.RegularExpressions.RegexOptions.IgnoreCase)
End Function
与延伸方法在C#
public static bool IsGUID(this string text)
{
return Guid.TryParse(text, out Guid guid);
}