7

I have T4 template where I'd like to generate an .cs file.

I have an array of System.Data.DataColumn that i'd like to use as a private variables in my generated code file.

I'm using ColumnName as variable name, Value as variable value and DataType as variable data type.

I'm thinking on how do I initialize defined variables in this case:

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

I'd like to see output: private System.String col1 = "text";

Variable definition in T4 template:

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

I'm thinking about writing helper method, that will return variable initialization string for common data types. Something like:

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;
            }
        } 

If someone did something similar, could you advice if this is a good idea or it could be done in more convenient way? Maybe I should read something?

2
  • 1
    You could also initialize Value as it should be output in the results. Ie: "0" for int, @"""Text""" for text and so on. The compiler will detect any conversion errors when compiling the generated C# code. Commented Apr 24, 2013 at 5:52
  • The thing is that incoming set of fields, that I use to define variables will change often, so I don't want to see compiling errors. Commented Apr 24, 2013 at 8:03

3 Answers 3

3
+50

This should work fine, although I would make it a generic class. Something like

internal class DataType<T>
{
      public string Name {get;set}
      public T Value {get;set;}
      public Type Type
      {
          get { return typeof(T); }
      }

      public string VariableDefinition()
      {
          /* Construct string */
      }
}

This would more flexible and reusable. Example usage:

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

private <#= dataType.VariableDefinition() #>
Sign up to request clarification or add additional context in comments.

Comments

1

Hope this works.

Use ExpandoObject to solve your problem. Definition of ExpandoObject as per MSDN :

It represents an object whose members can be dynamically added and removed at run time.

To set datatype and value at runtime , use Convert.ChangeType method. This creates an object of same type and value as you provide.

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

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

So create properties dynamically using ExpandoObject and create datatype dynamically using Convert.ChangeType.

Code :

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); 
        }
    }

}

Comments

1

Define a dictionary:

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) }
};

Then write a method like this:

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)));
}

And call it, like that:

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

Or even (not really reusable):

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)));
}

With:

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.