2013-04-23 5 views
7

Mam szablon T4, na którym chciałbym wygenerować plik .cs.Jak zainicjować różne zmienne typu w dynamicznie generowanym kodzie C#?

Mam tablicę System.Data.DataColumn, który chciałbym użyć jako prywatne zmienne w moim wygenerowanym pliku kodu.

Używam ColumnName jako nazwa zmiennej, Value jako wartość zmiennej, a DataType jako zmienny typ danych.

myślę o tym, jak mogę zainicjować zmienne zdefiniowane w tym przypadku:

ColumnName = "col1" 
ColumnValue = "text" 
DatType = System.String 

Chciałbym zobaczyć wyjście: private System.String col1 = "text";

definicji zmiennej w szablonie T4:

private <#= DataType.ToString() #> <#= ColumnName #> = "<=# ColumnValue #>" 

Zastanawiam się nad napisaniem metody pomocniczej, która zwróci zmienną ciąg inicjujący dla typowych typów danych. Coś takiego:

public string ValueInitializerString 
     { 
      get 
      { 

       string valueString; 
       if (this.DataType == typeof(int)) 
       { 
        valueString = this.Value.ToString(); 
       } 
       else if (this.DataType == typeof(string)) 
       { 
        valueString = string.Format("\"{0}\"", this.Value); 
       } 
       else if (this.DataType == typeof(DateTime)) 
       { 
        DateTime dateTime = (DateTime)this.Value; 

        valueString = string.Format("new DateTime({0}, {1}, {2}, {3}, {4}, {5}, {6})", 
                   dateTime.Year, dateTime.Month, dateTime.Day, dateTime.Hour, dateTime.Minute, dateTime.Second, dateTime.Millisecond); 
       } 
       else 
       { 
        throw new Exception(string.Format("Data type {0} not supported. ", this.DataType)); 
       } 
       return valueString; 
      } 
     } 

Jeśli ktoś zrobił coś podobnego, mógłbyś doradzić, czy to dobry pomysł, czy można to zrobić w bardziej wygodny sposób? Może powinienem coś przeczytać?

+1

Można również zainicjować wartości jak powinno być wyjście w wynikach. Tzn .: "0" dla int, @ "" "Tekst" "" dla tekstu i tak dalej. Kompilator wykryje wszelkie błędy konwersji podczas kompilowania wygenerowanego kodu C#. – FuleSnabel

+0

Chodzi o to, że przychodzący zestaw pól, których używam do definiowania zmiennych, często się zmienia, więc nie chcę widzieć błędów kompilacji. – Sergejs

Odpowiedz

3

To powinno działać dobrze, chociaż sprawiłoby, że byłaby to klasa ogólna. To coś bardziej elastycznego i wielokrotnego użytku. Przykład użycia:

<# 
var dataType = new DataType<String>() 
{ 
    Name = "col1", 
    Value = "text" 
}; 
#> 

private <#= dataType.VariableDefinition() #> 
1

Mam nadzieję, że to działa.

Użyj ExpandoObject, aby rozwiązać swój problem. Definicja ExpandoObject na MSDN:

Reprezentuje obiekt, którego członkowie mogą być dynamicznie dodawane i usuwane w czasie wykonywania.

Aby ustawić typ danych i wartość w czasie wykonywania, należy użyć metody Convert.ChangeType. Spowoduje to utworzenie obiektu o tym samym typie i wartości, jaki podasz.

Odesłanie ExpandoObject: https://blogs.msdn.microsoft.com/csharpfaq/2009/09/30/dynamic-in-c-4-0-introducing-the-expandoobject/

Odesłanie Convert.ChangeType: https://msdn.microsoft.com/en-us/library/system.convert.changetype(v=vs.110).aspx

Więc utworzyć właściwości dynamicznie przy użyciu ExpandoObject i utworzyć typ danych dynamicznie przy użyciu Convert.ChangeType.

Kod:

class Program 
{ 
     static void Main(string[] args) 
     { 
     // I have used hardcoded values representing database values 
     var dataTable = new DataTable(); 
     dataTable.Columns.Add(new DataColumn("Column1")); 
     dataTable.Columns.Add(new DataColumn("Column2")); 
     var row = dataTable.NewRow(); 
     row[0] = 1; 
     row[1] = "Test Value"; 
     dataTable.Rows.Add(row); 

     // This list below contains properties - variables , with same datatype and value 
     dynamic parentList = new List<dynamic>(); 

     var rowOne = dataTable.Rows[0]; 
     for (int i = 0; i < dataTable.Columns.Count; i++) 
     { 
      dynamic child= new ExpandoObject(); 

      child.Property = Convert.ChangeType(row[i], row[i].GetType()); 
      parentList.Add(child); 
     } 
    } 

} 
1

Zdefiniuj słownika:

var _valueConverters = new Dictionary<Type, Func<object, string>>() 
{ 
    { typeof(int), x => x.ToString() }, 
    { typeof(string), x => "\"" + x + "\"" }, 
    { typeof(DateTime), x => String.Format("new DateTime({0})", ((DateTime)x).Ticks) } 
}; 

następnie napisać metodę tak:

void WriteVariable<T>(string name, string value) 
{ 
    Type typeT = typeof(T); 
    if (! _valueConverters.ContainsKey(typeT)) 
     throw new Exception(string.Format("Data type {0} not supported. ", typeT.Name)); 
    Write(String.Format("{0} {1} = {2}", typeT.Name, name, _valueConverters[typeT](value))); 
} 

i nazwać go tak:

Albo nawet (nie naprawdę wielokrotnego użytku):

void WriteVariable<T>(string name, string value) 
{ 
    Type typeT = typeof(T); 
    if (! _valueConverters.ContainsKey(typeT)) 
     throw new Exception(string.Format("Data type {0} not supported. ", typeT.Name)); 
    Write(String.Format("private {0} {1} = {2};", typeT.Name, name, _valueConverters[typeT](value))); 
} 

Z:

<#= WriteVariable<string>("col1", "text") #>