[C#] 예외가 발생하지 않고 string이 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;
    }
}

적합하지 않습니다.

RegEx를 사용하려고 시도하지만 guid를 괄호로 묶거나 괄호로 묶을 수 있으며 랩핑을 할 수 없으므로 어렵게 만듭니다.

또한 특정 Guid 값이 유효하지 않다고 생각했습니다 (?)


업데이트 1

ChristianKFormatException모두가 아니라 잡는 것이 좋습니다 . 제안을 포함하도록 질문의 코드 샘플을 변경했습니다.


업데이트 2

예외 발생에 대해 왜 걱정해야합니까? 나는 종종 잘못된 GUID를 기대하고 있습니까?

대답은 ‘ 예’ 입니다. 나는 – 나는 TryStrToGuid을 사용하고 이유입니다 하고 잘못된 데이터를 기대.

예 1 폴더 이름에 GUID를 추가하여 네임 스페이스 확장명을 지정할 수 있습니다 . 폴더 이름을 파싱하여 final 다음에 텍스트가 있는지 확인합니다 . 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

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



답변

성능 벤치 마크

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을 사용하십시오.

String 표현의 guid를 Guid로 변환해야하는 경우

new Guid(someString);


답변

.net 4.0이 사용 가능하면을 사용할 수 있습니다 Guid.TryParse().


답변

당신은 이것을 좋아하지 않을 것입니다. 그러나 예외를 잡는 것이 느리다고 생각하게 만드는 것은 무엇입니까?

성공적인 GUID와 비교할 때 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가 많지 않기를 바랍니다.