Ну, у меня есть ответ сам. Я создал следующие файлы включения T4:
SignedIntegersSuffices.ttinclude
UnsignedIntegersSuffices.ttinclude
IntegersSuffices.ttinclude
FloatsSuffices.ttinclude
BasicTypesSuffices.ttinclude
, а затем фактический шаблон T4 - PointTypes.tt
. Эти файлы просто добавляются в проект C #, и Visual Studio обнаружит .tt
и сгенерирует соответствующий файл PointTypes.cs
при каждом сохранении файла .tt.
Эти файлы перечислены ниже.
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;
}
#>
И, наконец, фактический файл шаблона 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; }
}
<#
}
#>
}
Выходной файл PointTypes.cs
будет выглядеть следующим образом:
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; }
}
}
Довольно просто и довольно эффективно. Сейчас, конечно, это можно было бы сделать с помощью дженериков и т. Д., Но здесь дело не в этом. Это простой пример генерации кода для нескольких основных типов.
Комментарии для улучшения этого или аналогичного приветствуются.