Well, I have the answer my self. I have created the following T4 include files:
SignedIntegersSuffices.ttinclude
UnsignedIntegersSuffices.ttinclude
IntegersSuffices.ttinclude
FloatsSuffices.ttinclude
BasicTypesSuffices.ttinclude
and then the actual T4 template is PointTypes.tt
. These files are simply added to a C# project and Visual Studio will detect the .tt
and generate a matching PointTypes.cs
file, whenever the .tt file is saved.
These files are listed in the following.
SignedIntegersSuffices.ttinclude
<#+
IEnumerable<KeyValuePair<string, string>> SignedIntegersSuffices()
{
var signedIntegersSuffices = new KeyValuePair<string, string>[] {
new KeyValuePair<string, string>("sbyte", "I8"),
new KeyValuePair<string, string>("short", "I16"),
new KeyValuePair<string, string>("int", "I32"),
new KeyValuePair<string, string>("long", "I64")
};
return signedIntegersSuffices;
}
#>
UnsignedIntegersSuffices.ttinclude
<#+
IEnumerable<KeyValuePair<string, string>> UnsignedIntegersSuffices()
{
var signedIntegersSuffices = new KeyValuePair<string, string>[] {
new KeyValuePair<string, string>("byte", "UI8"),
new KeyValuePair<string, string>("ushort", "UI16"),
new KeyValuePair<string, string>("uint", "UI32"),
new KeyValuePair<string, string>("ulong", "UI64")
};
return signedIntegersSuffices;
}
#>
IntegersSuffices.ttinclude
<#@ include file="SignedIntegersSuffices.ttinclude" #>
<#@ include file="UnsignedIntegersSuffices.ttinclude" #>
<#+
// Insert any template procedures here
IEnumerable<KeyValuePair<string, string>> IntegersSuffices()
{
var integersSuffices = SignedIntegersSuffices().Concat(UnsignedIntegersSuffices());
return integersSuffices;
}
#>
FloatsSuffices.ttinclude
<#+
// Insert any template procedures here
IEnumerable<KeyValuePair<string, string>> FloatsSuffices()
{
var floatsSuffices = new KeyValuePair<string, string>[] {
new KeyValuePair<string, string>("float", "F32"),
new KeyValuePair<string, string>("double", "F64")
};
return floatsSuffices;
}
#>
BasicTypesSuffices.ttinclude
<#@ include file="IntegersSuffices.ttinclude" #>
<#@ include file="FloatsSuffices.ttinclude" #>
<#+
// Insert any template procedures here
IEnumerable<KeyValuePair<string, string>> BasicTypesSuffices()
{
var basicTypesSuffices = IntegersSuffices().Concat(FloatsSuffices());
return basicTypesSuffices;
}
#>
And finally the actual template file PointTypes.tt
:
<#@ template inherits="Microsoft.VisualStudio.TextTemplating.VSHost.ModelingTextTransformation" language="C#v3.5" debug="true" hostSpecific="true" #>
<#@ output extension=".cs" #>
<#@ Assembly Name="System.dll" #>
<#@ Assembly Name="System.Core.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Diagnostics" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ include file="BasicTypesSuffices.ttinclude" #>
namespace TextTemplatesTest
{
<#
const string pointPrefix = "Point";
foreach (var typeSuffix in BasicTypesSuffices())
{
string type = typeSuffix.Key;
string suffix = typeSuffix.Value;
#>
public struct <#= pointPrefix #><#= suffix #>
{
<#= pointPrefix #><#= suffix #>(<#= type #> x, <#= type #> y)
: this()
{
X = x;
Y = y;
}
public <#= type #> X
{ get; set; }
public <#= type #> Y
{ get; set; }
}
<#
}
#>
}
The output file PointTypes.cs
will then look like this:
namespace TextTemplatesTest
{
public struct PointI8
{
PointI8(sbyte x, sbyte y)
: this()
{
X = x;
Y = y;
}
public sbyte X
{ get; set; }
public sbyte Y
{ get; set; }
}
public struct PointI16
{
PointI16(short x, short y)
: this()
{
X = x;
Y = y;
}
public short X
{ get; set; }
public short Y
{ get; set; }
}
public struct PointI32
{
PointI32(int x, int y)
: this()
{
X = x;
Y = y;
}
public int X
{ get; set; }
public int Y
{ get; set; }
}
public struct PointI64
{
PointI64(long x, long y)
: this()
{
X = x;
Y = y;
}
public long X
{ get; set; }
public long Y
{ get; set; }
}
public struct PointUI8
{
PointUI8(byte x, byte y)
: this()
{
X = x;
Y = y;
}
public byte X
{ get; set; }
public byte Y
{ get; set; }
}
public struct PointUI16
{
PointUI16(ushort x, ushort y)
: this()
{
X = x;
Y = y;
}
public ushort X
{ get; set; }
public ushort Y
{ get; set; }
}
public struct PointUI32
{
PointUI32(uint x, uint y)
: this()
{
X = x;
Y = y;
}
public uint X
{ get; set; }
public uint Y
{ get; set; }
}
public struct PointUI64
{
PointUI64(ulong x, ulong y)
: this()
{
X = x;
Y = y;
}
public ulong X
{ get; set; }
public ulong Y
{ get; set; }
}
public struct PointF32
{
PointF32(float x, float y)
: this()
{
X = x;
Y = y;
}
public float X
{ get; set; }
public float Y
{ get; set; }
}
public struct PointF64
{
PointF64(double x, double y)
: this()
{
X = x;
Y = y;
}
public double X
{ get; set; }
public double Y
{ get; set; }
}
}
Pretty simple and quite effective. Now, of course, this could have been done using generics etc, but that is not the point here. This is meant as a simple example of code generation for multiple basic types.
Comments to improve this or similar are welcomed.