2012-06-02 3 views
1

모든 문자열을 강력한 형식의 목록으로 분할 할 수있는 분할 확장을 만들고 싶습니다. 나는 머리를 짚지 만, 많은 프로젝트에서 이것을 재사용 할 것이기 때문에 공동체로부터 의견을 얻고 싶습니다. (그래서 당신 자신의 도구 상자에 추가 할 수 있습니다.) 여기에서 아이디어가 있습니까?일반 유형의 스플릿 문자열 확장?

public static class Converters 
{ 
    public static IEnumerable<T> Split<T>(this string source, char delimiter) 
    { 
     var type = typeof(T); 

     //SPLIT TO INTEGER LIST 
     if (type == typeof(int)) 
     { 
      return source.Split(delimiter).Select(n => int.Parse(n)) as IEnumerable<T>; 
     } 

     //SPLIT TO FLOAT LIST 
     if (type == typeof(float)) 
     { 
      return source.Split(delimiter).Select(n => float.Parse(n)) as IEnumerable<T>; 
     } 

     //SPLIT TO DOUBLE LIST 
     if (type == typeof(double)) 
     { 
      return source.Split(delimiter).Select(n => double.Parse(n)) as IEnumerable<T>; 
     } 

     //SPLIT TO DECIMAL LIST 
     if (type == typeof(decimal)) 
     { 
      return source.Split(delimiter).Select(n => decimal.Parse(n)) as IEnumerable<T>; 
     } 

     //SPLIT TO DATE LIST 
     if (type == typeof(DateTime)) 
     { 
      return source.Split(delimiter).Select(n => DateTime.Parse(n)) as IEnumerable<T>; 
     } 

     //USE DEFAULT SPLIT IF NO SPECIAL CASE DEFINED 
     return source.Split(delimiter) as IEnumerable<T>; 
    } 
} 
나는 변환 기능에 대한 매개 변수를 추가 할 것
+0

여러 개의 단일 if 문 대신에 else를 사용해야합니다. 오직 하나만 일치 할 것입니다. – mfussenegger

+1

@mfussenegger : 각'if' 블록에'return' 문이 있기 때문에'else'가 중복됩니다. – Douglas

+1

일반 메서드가 제네릭 매개 변수의 형식을 테스트하는 데 의존하는 경우 IMO는 제네릭의 적절한 후보가 아닙니다. – spender

답변

5

나는 대통령의 제안에 동의하지만, 나는 개인적으로 생각하지 않습니다 표준 LINQ 작업을 통해 쉽게 달성 할 수있는 새로운 확장 방법을 정의 할 가치가 있습니다.

IEnumerable<int> ints = "1,2,3".Split(',').Select(int.Parse); 
+1

동의해야합니다. 이 답변의 간결함을 감안할 때 확장 메서드로 회전하면 노이즈가 추가 될뿐입니다. – spender

9

:

public static IEnumerable<T> Split<T>(this string source, Func<string, T> converter, params char[] delimiters) 
{ 
    return source.Split(delimiters).Select(converter); 
} 

그리고 당신은 내가 또한 String.Split와 혼동을 피하기 위해 이름을 변경 고려할 것

IEnumerable<int> ints = "1,2,3".Split<int>(int.Parse, ','); 

로 호출 할 수 있습니다 인스턴스 메서드를 사용하면 과부하 해결이 복잡해지며 다른 메서드와 다르게 동작합니다.

편집 :이 변환이 아니라 미리 정의 된 목록에 의존하기보다는 다른 유형으로 확장 할 수 있습니다

public static IEnumerable<T> SplitConvert<T>(this string str, params char[] delimiters) 
{ 
    var converter = TypeDescriptor.GetConverter(typeof(T)); 
    if (converter.CanConvertFrom(typeof(string))) 
    { 
     return str.Split(delimiters).Select(s => (T)converter.ConvertFromString(s)); 
    } 
    else throw new InvalidOperationException("Cannot convert type"); 
} 

: 당신이 변환 기능을 지정하지 않으려면, 당신은 형 컨버터를 사용할 수 있습니다 .

+0

감사합니다. 그러나 함수를 전달해야한다면 제네릭 형식 및 쉬운 재사용의 목적을 다소 상실 할 수 있습니다. – Basem

2
public static IEnumerable<T> Split<T> 
     (this string source, char delimiter,Converter<string,T> func) 
{ 
    return source.Split(delimiter).Select(n => func(n))); 
} 

예 :

"...".Split<int>(',',p=>int.Parse(p)) 

또는 당신은 Converter.ChangeType를 사용하지 않고 함수를 정의 할 수 있습니다

public static IEnumerable<T> Split<T>(this string source, char delimiter) 
{ 
    return source.Split(delimiter).Select(n => (T)Convert.ChangeType(n, typeof(T))); 
} 
+1

+1하지만, "..."대신에 Split (',', int.Parse)'를 사용하는 것이 더 간결 할 수 있습니다. split (',', p = > int.Parse (p))' – phoog

+0

@phoog, 제 생각에는 p => int.Parse (p)는 int보다 더 유연합니다. Parse (p => int와 같은 int.Parse() 오버로드를 사용할 수 있기 때문입니다. Parse (p ,, System.Globalization.NumberStyles.AllowDecimalPoint). –

1

이 방법은 좋지 않습니다. int보다 복잡한 데이터 유형을 처리 할 때는 문자열에서 데이터 유형을 파싱 (역 직렬화의 일종)하는 것은 유형 및 내용에 민감한 프로세스입니다. 예를 들어, DateTime.Parseusing the current culture 날짜를 구문 분석하므로 시스템에서 날짜에 대해 일관되거나 안정적인 출력을 제공하지 않습니다. 또한 날짜를 구문 분석하려고 시도하기 때문에 어떤 상황에서는 잘못된 입력으로 간주 될 수있는 내용을 건너 뛸 수 있습니다.

임의의 문자열을 강력한 형식의 목록으로 분할하는 목표는 특히 하드 코드 된 변환을 사용하는 단일 방법으로는 달성 할 수 없습니다. 특히 목표가 광범위한 유용성 인 경우 특히 그렇습니다. 새로운 전환으로 반복해서 업데이트하더라도 그것에 대해 갈 수있는 가장 좋은 방법은 위에 제안 된 Douglas처럼 "1,2,3".Split(",").Select(x => whatever)입니다. 어떤 종류의 전환이 일어나고 있는지 또한 매우 분명합니다.