2014-10-21 9 views
0

나는 xml을 읽고 데이터베이스에 데이터를 쓰는 일반 메소드를 작성하려고하는데 문제가있다.결과 형식을 지정하지 않고 C#에서 함수 참조를 전달할 수있는 방법이 있습니까?

이 경우 데이터가 프로그램의 다른 사본에 의해 직렬화되었습니다.

xml의 항목을 SqlParameter에 추가하기 전에 유틸리티 파일의 여러 가지 "고정"방법 중 하나를 통해 해당 항목을 실행해야합니다.

필요한 특정 메서드가 전달되어야하므로 문자열로 전달하고 스위치 구조를 사용하여 리플렉션을 기본 사례로 호출 할 방법을 결정해야합니다.

int, string, bool, decimal, double 또는 DateTime을 반환하도록 지정하지 않고 메서드 참조를 실제로 전달할 방법이 있는지 궁금합니다.

Func을 사용해 보았지만 결과 유형이 필요합니다. 이 유틸리티 기능 모든 매개 변수로 대상을 Tuple<string,Func<?>[] parameters

:

새로운 인수는 아마 같은 것을 보일 것이다.

Func Return Any Type

내 현재 코드 :

private void SaveBundleToTable<T1, T2> 
(
    string xmlData, 
    string table, 
    string storedProcedure, 
    Tuple<string, string>[] parameters 
) 
    where T1 : DataSet, new() 
    where T2 : DataRow 
{ 
    T1 BundleData = new T1(); 
    BundleData.Clear(); 
    StringReader theReader = new StringReader(xmlDataset); 
    BundleData.ReadXml(theReader); 
    foreach (T2 item in BundleData.Tables[table].Rows) 
    { 
     SqlCommand _cmd = new SqlCommand(storedProcedure, [SQLConnection]); 
     _cmd.CommandType = CommandType.StoredProcedure; 
     foreach (var par in parameters) 
     { 
      var _param = getSqlParameter<T2>(item, par.First, par.Second); 
      _cmd.Parameters.Add(_param); 
     } 
     _cmd.ExecuteNonQuery(); 
    } 
} 

나는 나는 그들이 모두 다를 수 있습니다 목록이없는 것을 제외하고 무엇을 찾고 거의있는 질문을 발견 별도의 방법으로 구조체 전환 :

private SqlParameter getSqlParameter<T>(T item, string columnName, string method) where T : DataRow 
{ 
    switch (method) 
    { 
     case "FixString": 
      return new SqlParameter(columnName, util.FixString(item[columnName])); 
     case "FixInt": 
      return new SqlParameter(columnName, util.FixInt(item[columnName])); 
     case "FixBooleanToInt": 
      return new SqlParameter(columnName, util.FixBooleanToInt(item[columnName])); 
     case "FixBoolean": 
      return new SqlParameter(columnName, util.FixBoolean(item[columnName])); 
     case "FixFloat": 
      return new SqlParameter(columnName, util.FixFloat(item[columnName])); 
     case "FixDouble": 
      return new SqlParameter(columnName, util.FixDouble(item[columnName])); 
     case "FixDate": 
      return new SqlParameter(columnName, util.FixDate(item[columnName])); 
     case "FixDateForZeroTime": 
      return new SqlParameter(columnName, util.FixDateForZeroTime(item[columnName])); 
     case "FixDecimal": 
      return new SqlParameter(columnName, util.FixDecimal(item[columnName])); 
     default: 
      try 
      { 
       Type thisType = util.GetType(); 
       MethodInfo theMethod = thisType.GetMethod(method); 
       return new SqlParameter(columnName, theMethod.Invoke(this, new object[]{item[columnName]})); 
      } 
      catch (Exception ex) 
      { 
       throw new Exception("Unknown utility method: " + method,ex); 
      } 
    } 
} 

편집 1 :

난 그냥 Tuple<string,Func<object,dynamic>>의 매개 변수 유형을 사용하여 시도하고 그것이이 프로젝트는 닷넷 3.5에, 참고로 Tuple<string,?>

의 유형을 판별 할 수 없습니다 말했다로 컴파일하지 않을

그래서 구현 이 질문에 설명 된대로 튜플의 로컬 버전 :

Equivalent of Tuple (.NET 4) for .NET Framework 3.5

편집 2 : 나는 일반적인 방법을 변경 한 경우 그래서 배열을 전달할 수 있습니다

나는 당신이 단지 util.Fix (객체 O를 가지고 있어야 Tuple.New<string, Func<object,decimal>>

+0

fml을 읽는 DataSets는 프로그램에 의해 시행되며 변경할 수 없습니다. – OrangeKing89

+0

Delegate를 대리자 형식으로 항상 사용할 수 있습니다.이 형식은 대리자 형식의 기본 형식이며 일반적으로 서명을 적용하지 않습니다. 어쨌든 당신이 리플렉션을 통해 호출하기 때문에, 나는 당신을 위해 괜찮을 것이라고 기대할 것입니다. –

+0

@PeterDuniho 여기서 반사를 사용하지 않는 것이 좋습니다. switch 문이 정의 된 경우에 메서드를 가지고 있지 않다면 지금은 단지 fallback으로 사용하고 있습니다. – OrangeKing89

답변

0

내가 일을 전달하는 기능을 만들 수있는 방법을 알아낼했다하지만이 방법은 내 상황이 너무 장황. 나는이 작업을 수행하는 더 간결한 방법을 찾을하지 않는 한

new Tuple<string, Func<object,object>>[] 
{ 
    Tuple.New<string, Func<object,object>>("LAB_CODE",util.FixString), 
    Tuple.New<string, Func<object,object>>("MORM_SELL",x => (object)util.FixDecimal(x)), 
... 

나는 내 switch 문을 고수 것이라 생각합니다.

편집 :

new Tuple<string, Func<object,object>>[] 
{ 
    Tuple.Util<string>("LAB_CODE",util.FixString), 
    Tuple.Util<decimal>("MORM_SELL",util.FixDecimal), 
... 

이 될 수 :

public static Tuple<string, Func<object, object>> Util<T>(string first, Func<object, T> second) 
{ 
    Func<object, object> method = getFunc<T>(second); 
    var tuple = new Tuple<string, Func<object, object>>(first, method); 
    return tuple; 
} 
private static Func<object,object> getFunc<T>(Func<object,T> method) 
{ 
    return x => (object)method(x); 
} 

이 날 매개 변수 전달이 구문을 사용할 수 있습니다 : 내 정적 튜플 클래스에이 기능을 추가

닷넷 4 튜플 클래스와 함께 사용하는 확장 함수로 구현

0

를 사용하는 경우

new Tuple<string, Func<object,object>>[] 
    { 
     Tuple.New<string, Func<object,object>>("LAB_CODE",util.FixString), 
     Tuple.New<string, Func<object,object>>("MORM_SELL",util.FixDecimal), 
    ... 

더 큰 오류가 : 나는 소수 줄에 컴파일 오류를 호출 할 때 다음 Tuple<string,Func<object,object>>을 입력) 함수는 다음을 통해 코드를 결정하여 올바른 픽스를 반환합니다.

이것은 관리하는 것과 비슷하지만 관리를 정리합니다. 데이터 유형별로 다른 논리를 사용하기 때문에 일종의 if 문을 수행해야하는 상황에 처하게됩니다.

클래스의 경우 수정을 위해 정의 된 필요한 메소드가있는 인터페이스 만 작성하십시오.

+0

나는 이것 또한 시도했다. 이 문제는 동일한 유형을 반환하는 몇 가지 다른 "수정"메소드가 있다는 것입니다 :'bool util.FixBoolean (object o)'&'bool util.FixBooleanToInt (object o)'. 나는 이들에 대한 다른 유스 케이스가 무엇인지 모르겠습니다. – OrangeKing89

+0

'float','decimal' 또는'double'을 사용하는 몇몇 다른 메소드에 문제가있을 수도 있습니다. 왜냐하면 항상 정확하게 평가할 지 확신 할 수 없기 때문입니다. – OrangeKing89

+0

개체를 반환하는 한 SqlParameter를 사용하면 항상 논리가 더 깊어 질 수 있습니다. (o가 bool 인 경우) {if (논리가 int로 변환) util.FixBooleanToInt (o) else util.FixBoolean (o); } – zam664

0

Func<object, object>을 사용할 수 없습니까? 반환 유형이 객체가 아니더라도 여전히 컴파일 할 수 있습니다. 여기에 내가 VS 2013를 테스트 한 예입니다

public static string FixString(object data) 
{ 
    return null; 
} 

static void Main(string[] args) 
{ 
    DataRow row = null; 
    SqlParameter param = getSqlParameter(row, "Address", FixString); 
} 

private static SqlParameter getSqlParameter<T>(T item, string columnName, Func<object, object> method) where T : DataRow 
{ 
    return new SqlParameter(columnName, method(item[columnName])); 
} 
+0

int 또는 다른 기본 유형을 반환하는 메서드를 전달하면 암시 적으로 어떤 이유로 든 변환되지 않습니다. 또한 나는 하나의 함수 만 전달하는 것이 아니라 SQL 매개 변수의 필요성에 따라 함수 배열을 전달합니다. 지금은 함수의 이름을'Tuple [] parameters'의 두 번째 부분으로 문자열로 전달하고 switch 문에 함수에 매핑합니다. – OrangeKing89