2010-02-24 3 views
1

DataRow에 값을 채우는 데 "형식에 독립적"메서드를 구현하고 있습니다.C#의 동적 문자열 구문 분석

private void FillDataRow(List<ColumnTypeStringRep> rowInput, DataRow row) 

ColumnTypeStringRep 구조 값, 열 이름의 문자열 표현을 포함하고 - 무엇이다 : 발신자가 작성 될 필요가 열 값과의 DataRow의 문자열 표현의 컬렉션을 통과 - 의도 된 기능은 매우 정직 가장 중요한 것 - 열 데이터 형식 :

private struct ColumnTypeStringRep 
{ 
    public string columnName; public Type type; public string stringRep; 
    public ColumnTypeStrinRep(string columnName, Type type, string stringRep) 
    { 
     this.columnName = columnName; this.type = type; this.stringRep = stringRep; 
    } 
} 

그래서 "유형 독립성"은 무엇입니까? 기본적으로 전달 된 열 이름이 DataRow의 열 이름과 일치하고 DataRow의 열 데이터 유형과 일치하는 한 데이터 행 스키마 (항상 형식이 지정된 데이터 테이블의 행)는 상관하지 않습니다. 이 함수는 가능한 한 유연해야합니다 (가능한 한 간단하고 단순하지는 않음). 는 여기가 (거의)입니다 :

private void FillDataRow(List<ColumnTypeStrinRep> rowInput, DataRow row) 
{ 
Debug.Assert(rowInput.Count == row.Table.Columns.Count); 

foreach (ColumnTypeStrinRep columnInput in rowInput) 
{ 
    Debug.Assert(row.Table.Columns.Contains(columnInput.columnName)); 
    Debug.Assert(row.Table.Columns[columnInput.columnName].DataType == columnInput.type); 

    // --> Now I want something more or less like below (of course the syntax is wrong) : 

    /* 
    row[columnInput.columnName] = columnInput.type.Parse(columnInput.stringRep); 
    */ 

    // --> definitely not like below (this of course would work) : 

    /* 
    switch (columnInput.type.ToString()) 
    { 
     case "System.String": 
      row[columnInput.columnName] = columnInput.stringRep; 
      break; 
     case "System.Single": 
      row[columnInput.columnName] = System.Single.Parse(columnInput.stringRep); 
      break; 
     case "System.DateTime": 
      row[columnInput.columnName] = System.DateTime.Parse(columnInput.stringRep); 
      break; 
     //... 
     default: 
      break; 
    } 
    */ 
} 

}

이제 당신은 아마 내 문제를 볼 - 나는 스위치 문을 사용하지 않습니다. 첫 번째 주석 처리 된 세그먼트에서와 마찬가지로, 제공된 문자열 유형을 사용하여 문자열 표현으로 생성 된 해당 유형의 객체를 반환하는 특정 유형의 Parse 메소드를 호출하는 것이 좋습니다. 스위치 솔루션은 작동하지만 매우 유연하지 않습니다. 앞으로는 DataRow가 아니라 다른 유형의 사용자 정의 유형도 사용자 정의 유형의 "열"로 채우게 될 것입니다 (당연히 이러한 모든 유형은 Parse 메소드를 노출해야합니다 문자열 표현으로부터 스스로를 구축하기 위해).

당신은 내가 말한 것을 얻을 수 있기를 바랍니다. 마치 "동적 파싱"과 같은 기능입니다. .NET에서이를 달성 할 수있는 방법이 있습니까? FillDataRow 호출의

예는 다음과 같이 수 :

List<ColumnTypeStrinRep> rowInput = new List<ColumnTypeStrinRep>(); 
rowInput.Add(new ColumnTypeStringRep("colName1", Type.GetType("System.Int32"), "0")); 
rowInput.Add(new ColumnTypeStringRep("colName2", Type.GetType("System.Double"), "1,11")); 
rowInput.Add(new ColumnTypeStringRep("colName3", Type.GetType("System.Decimal"), "2,22")); 
rowInput.Add(new ColumnTypeStringRep("colName4", Type.GetType("System.String"), "test")); 
rowInput.Add(new ColumnTypeStringRep("colName5", Type.GetType("System.DateTime"), "2010-01-01")); 
rowInput.Add(new ColumnTypeStringRep("colName6", Type.GetType("System.Single"), "3,33")); 

TestDataSet.TestTableRow newRow = this.testDataSet.TestTable.NewTestTableRow(); 
FillDataRow(rowInput, newRow); 
this.testDataSet.TestTable.AddTestTableRow(newRow); 
this.testDataSet.TestTable.AcceptChanges(); 

당신을 감사합니다!

답변

2

TypeConverter 클래스 형식을 변환하는 일반적인 .NET의 방법입니다 말했다. System.ComponentModel 네임 스페이스에는 기본 유형에 대한 구현이 포함되어 있으며 WPF에는 더 많은 네임 스페이스가 포함되어 있습니다 (그러나 네임 스페이스에는 확실하지 않습니다). 게다가 원시 타입 변환을 제공하는 정적 인 Convert 클래스가 있습니다. 간단한 전환을 처리하고 IConvertible으로 돌아갑니다.

+0

고맙습니다. - 곧 확인하겠습니다. 유망 해 보인다. "순수한"리플렉션에 대해서도 생각하고있었습니다. 특정 형식에 대해 GetMethod ("Parse")를 사용하여 MethodInfo를 통해 Parse를 호출했습니다. 올바른 방법인지 확실하지 않아 제대로 작동하지 않습니다. – garret

+0

좋은 답변입니다. .NET TypeConverters를 잊어 버렸습니다. – jrista

+0

Convert 클래스의 작은 부록. 당신은 Convert.ChangeType() 메서드를 사용하여 기본 요소뿐만 아니라 모든 것을 변환 할 수 있어야합니다. TypeConverter가있는 한 ChangeType 메서드는 형식 변환기를 찾아서 소스 및 대상 형식이 사용 가능한 어셈블리의 일부 변환기에서 지원되는 한 변환을 수행해야합니다. – jrista

0

먼저 구조체를 사용하여 복잡한 데이터를 전달합니다. 그것은 정말 나쁜 생각입니다. 대신 수업을 만들어보세요.

interface IColumnTypeParser 
{ 
    // A stateles Parse method that takes input and returns output 
    DataColumn Parse(string input); 
} 

class ColumnTyeParserFactory 
{ 
    IColumnTypeParser GetParser(Type columnType) 
    { 
     // Implementation can be anything you want...I would recommend supporting 
     // a configuration file that maps types to parsers, and use pooling or caching 
     // so you are not constantly recreating instances of your parsers (make sure your 
     // parser implementations are stateless to support caching/pooling and reuse) 

     // Dummy implementation: 
     if (columnType == typeof(string)) return new StringColumnTypeParser(); 
     if (columnType == typeof(float)) return new FloatColumnTypeParser(); 
     // ... 
    } 
} 

공장 사용 hten 것입니다 귀하의 FillDataRow 구현 : 즉

m_columnTypeParserFactory = new ColumnTypeParserFactory(); 

private void FillDataRow(List<ColumnTypeStrinRep> rowInput, DataRow row) 
{ 
    foreach (ColumnTypeStrinRep columnInput in rowInput) 
    { 
     var parser = m_columnTypeParserFactory.GetParser(columnInput.type); 
     row[columnInput.columnName] parser.Parse(columnInput.stringRep); 
    } 
} 
+0

나는 구조에 동의하지만, 형식 변환을 재발견 할 필요가 없습니다. –

+0

구조 힌트를 가져 주셔서 감사합니다! 귀하의 솔루션은 좋은 디자인 패턴을 새로 - 청정하지만 그게 내가 무엇을 찾고 있었는지 - 그것은 단 한 곳에서 다른 곳으로 (ColumnTypeParserFactory로) switch 문을 이동합니다. 나는 더 많은 ".NET automagicall"을 유형 (reflection?)과 함께 사용하려고 생각하고있었습니다. 어쨌든 고마워! – garret

+0

@ 대니얼 : 아, 네 말이 맞다! .NET TypeConversion을 사용하지는 않았지만 훨씬 나은 솔루션입니다. 그 대답은 공장 패턴의 학문적 연구로 남겨 둡니다. ;) – jrista

0

아무것도 없다 당신이 파서 인터페이스의 인스턴스를 만드는 공장이 필요한 것처럼 말했다

, 그것은 소리 그처럼 - 자동적 인 변환은 없습니다. 스스로 전환을 지정해야합니다. 즉

static class Converters{ 
    static Dictionary<Type, Func<string, object>> Converters = new ... 

    static Converters{ 
     Converters.Add(typeof(string), input => input); 
     Converters.Add(typeof(int), input => int.Parse(input)); 
     Converters.Add(typeof(double), double => double.Parse(input)); 
    } 
} 

void FillDataRow(IList<string> rowInput, row){ 
    for(int i = 0; i < rowInput.Length; i++){ 
     var converter = Converters.Converters[Column[i].DataType]; 
     row[i] = converter(rowInput[i]) 
    } 
} 
+0

프레임 워크는 확장 가능한 유형 변환을위한 몇 가지 선택 사항을 제공합니다. –

+0

그게 사실 jrista 솔루션과 비슷합니다 (또는 그의 솔루션은 응답 시간에 따라 판단하는 것과 유사합니다). 그러나 저는 유형별로 제공 할 필요가없는 솔루션을 찾고 있습니다. 당신이나 당신의 람다. 그러나 당신의 솔루션은 아마도 내가 바라는 반사 마법을 사용하는 잠재적 인 것보다 훨씬 더 빠릅니다. 어쨌든 고마워! – garret

0

Convert.ChangeType은 어떻습니까?
generics btw로 멋진 것으로 생각할 수 있습니다.Convert.ChangeType에

foreach (ColumnTypeStrinRep columnInput in rowInput) 
{ 
    Debug.Assert(row.Table.Columns.Contains(columnInput.columnName)); 
    Debug.Assert(row.Table.Columns[columnInput.columnName].DataType == columnInput.type); 
    ... 
    row[columnInput.columnName] = Convert.ChangeType(columnInput.stringRep, columnInput.type); 
} 

더 :
http://msdn.microsoft.com/en-us/library/dtb69x08.aspx