T4(文本模板转换工具包),用于基于基本类型列表生成一组类型,例如C#中的PointI32,PointF32等

时间:2010-02-12 14:56:32

标签: c# .net visual-studio-2008 t4 dsl-tools

Boost Preprocessor library for generating a set of types based on a list of basic types e.g. PointI32, PointF32 etc. in C++/CLI类似,我问如何生成:

struct Point##TYPE_SUFFIX_NAME
{
    TYPE X
    { get; set; }
    TYPE Y;
    { get; set; }

    // Other code
};

用于不同的基本(POD)数据类型,例如:

PointF32, PointF64, PointI32 etc.

在Visual Studio 2008或更高版本中使用T4(文本模板转换工具包)。

请参阅http://www.olegsych.com/2007/12/text-template-transformation-toolkit/http://msdn.microsoft.com/en-us/library/bb126445.aspx

1 个答案:

答案 0 :(得分:2)

好吧,我有自己的答案。我创建了以下T4包含文件:

  • SignedIntegersSuffices.ttinclude
  • UnsignedIntegersSuffices.ttinclude
  • IntegersSuffices.ttinclude
  • FloatsSuffices.ttinclude
  • BasicTypesSuffices.ttinclude

然后实际的T4模板为PointTypes.tt。这些文件只是添加到C#项目中,只要保存.tt文件,Visual Studio就会检测.tt并生成匹配的PointTypes.cs文件。

以下列出了这些文件。

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

非常简单而且非常有效。当然,现在可以使用泛型等来完成,但这不是重点。这是一个用于多种基本类型的代码生成的简单示例。

欢迎提出改进或类似的评论。