예외를 발생시키지 않고 문자열이 guid인지 테스트하시겠습니까?

StackOverflow https://stackoverflow.com/questions/104850

  •  01-07-2019
  •  | 
  •  

문제

문자열을 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

크리스티안K 그냥 잡는 게 좋은 생각이었어 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 사용자가 입력한 검색 표현식을 구문 분석하는 중일 수 있습니다.

enter image description here

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

추신.나는 질문을 정당화할 필요가 없습니다.

도움이 되었습니까?

해결책

성능 벤치마크

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);

다른 팁

.net 4.0을 사용할 수 있게 되면 다음을 사용할 수 있습니다. Guid.TryParse().

당신은 이것을 좋아하지 않을 것이지만 예외를 잡는 것이 더 느려질 것이라고 생각하는 이유는 무엇입니까?

성공적인 시도와 비교하여 GUID 구문 분석 시도 실패 횟수는 몇 번이나 예상됩니까?

내 조언은 방금 만든 함수를 사용하고 코드를 프로파일링하라는 것입니다.이 기능이 실제로 핫스팟인 것으로 확인되면 그 다음에 고치되 이전에는 하지 마세요.

.NET 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;
}

SEHException, ThreadAbortException 또는 기타 치명적이거나 관련 없는 항목에 대해 "잘못된 GUID"라고 말하고 싶지 않습니다.

업데이트:.NET 4.0부터 Guid에 사용할 수 있는 새로운 메서드 세트가 있습니다.

실제로 이러한 항목을 사용해야 합니다(내부적으로 try-catch를 사용하여 "순진하게" 구현되지 않은 경우에만).

Interop은 단지 예외를 포착하는 것보다 느립니다.

10,000명의 가이드와 함께하는 행복한 길에서:

Exception:    26ms
Interop:   1,201ms

불행한 길에서:

Exception: 1,150ms
  Interop: 1,201ms

더 일관성이 있지만 지속적으로 느립니다.처리되지 않은 예외에서만 중단되도록 디버거를 구성하는 것이 더 나을 것 같습니다.

음, 여기에 필요한 정규 표현식이 있습니다.

^[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}(}})$

그러나 그것은 단지 시작을 위한 것입니다.또한 날짜/시간 등 다양한 부분이 허용 가능한 범위 내에 있는지 확인해야 합니다.이것이 이미 설명한 try/catch 방법보다 더 빠르다고는 상상할 수 없습니다.이러한 유형의 확인을 보장하기 위해 잘못된 GUID를 그렇게 많이 받지 않기를 바랍니다.

유용성상의 이유로 디버거가 팝업됩니다.

try/catch 접근 방식을 사용하려는 경우 [System.Diagnostics.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;
    }
}

내가 아는 한 mscrolib에는 Guid.TryParse와 같은 것이 없습니다.Reference Source에 따르면 Guid 유형에는 모든 종류의 guid 형식을 확인하고 구문 분석을 시도하는 매우 복잡한 생성자가 있습니다.리플렉션을 통해서도 호출할 수 있는 도우미 메서드가 없습니다.제 생각에는 타사 Guid 파서를 검색하거나 직접 작성해야 할 것 같습니다.

RegEx 또는 온전성 검사를 수행하는 일부 사용자 정의 코드를 통해 잠재적인 GUID를 실행하여 줄무늬가 최소한 GUID처럼 보이고 유효한 문자로만 구성되어 있는지 확인하십시오(그리고 전체 형식에 맞는 것 같을 수도 있음).온전성 검사를 통과하지 못하면 오류가 반환됩니다. 그러면 대부분의 유효하지 않은 문자열이 제거될 것입니다.

그런 다음 위와 같이 문자열을 변환하고 여전히 온전성 검사를 통과한 몇 가지 잘못된 문자열에 대한 예외를 포착합니다.

Jon Skeet은 Int 구문 분석과 유사한 분석을 수행했습니다(TryParse가 프레임워크에 포함되기 전). 문자열을 Int32로 변환할 수 있는지 확인

그러나 다음과 같이 앤서니W존스 아마도 이것에 대해 걱정하지 않아도 될 것이라고 지적했습니다.

 bool IsProbablyGuid(string s)
    {
        int hexchars = 0;
        foreach(character c in string s)
        {
           if(IsValidHexChar(c)) 
               hexchars++;          
        }
        return hexchars==32;
    }
  • 리플렉터 가져오기
  • 복사하여 붙여넣기 Guid의 .ctor(문자열)
  • "throw new ..."가 나타날 때마다 "return false"로 바꿉니다.

Guid의 ctor는 거의 컴파일된 정규식이므로 예외 오버헤드 없이 정확히 동일한 동작을 얻을 수 있습니다.

  1. 이것이 리버스 엔지니어링에 해당합니까?제 생각에는 그렇게 생각하며, 따라서 불법일 수도 있습니다.
  2. GUID 양식이 변경되면 중단됩니다.

더 멋진 솔루션은 "throw new"를 즉석에서 대체하여 메서드를 동적으로 계측하는 것입니다.

나는 위에 게시된 GuidTryParse 링크에 투표합니다. 또는 유사한 솔루션(IsProballyGuid).나는 변환 라이브러리와 같은 것을 작성할 것입니다.

나는 이 질문이 그렇게 복잡해야 한다는 것이 완전히 형편없다고 생각한다.Guid가 null일 수 있는 경우 "is" 또는 "as" 키워드는 괜찮습니다.그러나 어떤 이유에서인지 SQL Server는 괜찮지만 .NET은 그렇지 않습니다.왜?Guid.Empty의 값은 무엇입니까?이것은 .NET 설계로 인해 발생한 어리석은 문제일 뿐이며, 언어 규칙이 그 자체로 적용되면 정말 짜증납니다.지금까지 가장 성과가 좋은 답변은 프레임워크가 정상적으로 처리하지 못하기 때문에 COM Interop을 사용하는 것이었습니다."이 문자열이 안내가 될 수 있습니까?" 대답하기 쉬운 질문이어야합니다.

앱이 인터넷에 연결될 때까지 발생하는 예외에 의존하는 것은 괜찮습니다.그 시점에서 나는 서비스 거부 공격에 대비했습니다."공격"을 당하지 않더라도 일부 야후가 URL을 가지고 장난을 칠 것이라는 것을 알고 있습니다. 아니면 마케팅 부서에서 잘못된 링크를 보낼 수도 있고 그러면 내 애플리케이션이 가져올 수 있는 상당한 성능 저하를 겪게 될 수도 있습니다. 발생해서는 안 되는 문제를 처리하기 위해 코드를 작성하지 않았지만 우리 모두는 일어날 것이라는 것을 알고 있기 때문에 서버를 다운시켰습니다.

이로 인해 "예외"에 대한 경계가 약간 흐려집니다. 그러나 결론적으로 문제가 자주 발생하지 않더라도 애플리케이션이 충돌하여 모든 항목을 처리하는 데 충돌이 발생할 수 있는 경우 예외를 발생시키는 것은 다음과 같습니다. 나쁜 형태.

TheRage3K

TypeOf ctype(myvar,Object)가 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);
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top