понедельник, 22 июня 2026 г.

Deepseek, T4,Templates,(.tt), Generator, FractalCellSln.slnx

Deepseek, T4,Templates,(.tt), Generator, FractalCellSln.slnx

https://chat.deepseek.com/share/yo84sj7nbtpo0yiciv

--------------------------------------------------------------------------------------------------------------------------

D:\Projects\VS02\2606\FractalNet\DeepSeek\FractalCell\FractalCellSln\FractalCellSln.slnx

D:\Projects\VS02\2606\FractalNet\DeepSeek\FractalCell\FractalCellSln\FractalCell01\FractalCell01.csproj

-------------------------------------------------------------------------------------------------------------

T4 Templates (.tt) — это генераторы исходного кода в Visual Studio и .NET!

Что такое T4 (Text Template Transformation Toolkit):

Это технология, которая позволяет автоматически генерировать C# код на основе шаблонов. Вы пишете шаблон с логикой, а Visual Studio генерирует готовый .cs файл.

Простой пример T4 шаблона:

ChannelCellTemplate.tt — ШАБЛОН:

t4

<#@ template debug="true" hostspecific="true" language="C#" #>

<#@ output extension=".generated.cs" #>

<#@ parameter name="CellName" type="System.String" #>

<#@ parameter name="Capacity" type="System.Int32" #>

<#

    // Это C# код, который выполняется во время генерации

    string className = $"{CellName}ChannelCell";

    string busClassName = $"{CellName}ChannelBus";

#>

// Автоматически сгенерированный код из шаблона ChannelCellTemplate.tt

// Время генерации: <#= DateTime.Now #>

using System;

using System.Threading.Tasks;


namespace FractalCell.Generated

{

    public class <#= className #> : FractalCellTemplate<ChannelInternalBus, ChannelExternalBus>

    {

        private readonly int _capacity = <#= Capacity #>;

        

        public <#= className #>(

            CellConfiguration configuration,

            ChannelInternalBus internalBus,

            ChannelExternalBus externalBus)

            : base(configuration, internalBus, externalBus)

        {

        }


        protected override IEnumerable<BackgroundService> CreateBackgroundServices()

        {

            for (int i = 0; i < Configuration.BackgroundServiceCount; i++)

            {

                yield return new ChannelBackgroundService(

                    $"<#= CellName #>-worker-{i}",

                    InternalBus,

                    Logger,

                    Configuration);

            }

        }

        protected override void ConfigureHandlers()

        {

            InternalBus.Subscribe<FractalEvent>(async fractalEvent =>

            {

                Logger.LogInformation("<#= CellName #> received: {EventType}", 

                    fractalEvent.EventType);

                

                // Специфичная логика для <#= CellName #>

                await Process<#= CellName #>EventAsync(fractalEvent);

            });

        }

        private async Task Process<#= CellName #>EventAsync(FractalEvent @event)

        {

            // Кастомная обработка для этой ячейки

            Logger.LogInformation("Processing in <#= CellName #> cell with capacity <#= Capacity #>");

            

            switch (@event.EventType)

            {

                case "<#= CellName #>DataProcess":

                    // Специфичная обработка

                    break;

                default:

                    await ExternalBus.SendToCellAsync(@event.TargetCellId, @event);

                    break;

            }

        }

    }

}

Что получится при генерации:

При запуске шаблона с параметрами CellName = "Stratosphere" и Capacity = 5000 сгенерируется:


ChannelCellTemplate.generated.cs — РЕЗУЛЬТАТ:

csharp

// Автоматически сгенерированный код из шаблона ChannelCellTemplate.tt

// Время генерации: 22.06.2026 15:30:00


using System;

using System.Threading.Tasks;


namespace FractalCell.Generated

{

    public class StratosphereChannelCell : FractalCellTemplate<ChannelInternalBus, ChannelExternalBus>

    {

        private readonly int _capacity = 5000;

        

        public StratosphereChannelCell(

            CellConfiguration configuration,

            ChannelInternalBus internalBus,

            ChannelExternalBus externalBus)

            : base(configuration, internalBus, externalBus)

        {

        }

        protected override IEnumerable<BackgroundService> CreateBackgroundServices()

        {

            for (int i = 0; i < Configuration.BackgroundServiceCount; i++)

            {

                yield return new ChannelBackgroundService(

                    $"Stratosphere-worker-{i}",

                    InternalBus,

                    Logger,

                    Configuration);

            }

        }

        protected override void ConfigureHandlers()

        {

            InternalBus.Subscribe<FractalEvent>(async fractalEvent =>

            {

                Logger.LogInformation("Stratosphere received: {EventType}", 

                    fractalEvent.EventType);

                

                // Специфичная логика для Stratosphere

                await ProcessStratosphereEventAsync(fractalEvent);

            });

        }

        private async Task ProcessStratosphereEventAsync(FractalEvent @event)

        {

            // Кастомная обработка для этой ячейки

            Logger.LogInformation("Processing in Stratosphere cell with capacity 5000");

            

            switch (@event.EventType)

            {

                case "StratosphereDataProcess":

                    // Специфичная обработка

                    break;

                default:

                    await ExternalBus.SendToCellAsync(@event.TargetCellId, @event);

                    break;

            }

        }

    }

}

Продвинутый шаблон с конфигурацией из JSON:

TplCellTemplate.tt:

t4

<#@ template debug="true" hostspecific="true" language="C#" #>

<#@ output extension=".generated.cs" #>

<#@ assembly name="System.Core" #>

<#@ assembly name="System.Text.Json" #>

<#@ import namespace="System.IO" #>

<#@ import namespace="System.Text.Json" #>

<#@ import namespace="System.Collections.Generic" #>

<#

    // Читаем конфигурацию из JSON файла

    string configPath = Path.Combine(Path.GetDirectoryName(this.Host.TemplateFile), "cell-config.json");

    string jsonContent = File.ReadAllText(configPath);

    

    var configs = JsonSerializer.Deserialize<List<CellConfig>>(jsonContent);

    

    foreach(var config in configs)

    {

        GenerateCellClass(config);

    }

    

    void GenerateCellClass(CellConfig config)

    {

#>

// ===== Сгенерировано для ячейки: <#= config.Name #> =====

public class <#= config.Name #>TplFractalCell : FractalCellTemplate<TplInternalBus, TplExternalBus>

{

    private readonly int _maxParallelism = <#= config.MaxParallelism #>;

    private readonly string _region = "<#= config.Region #>";

    

    public <#= config.Name #>TplFractalCell(

        CellConfiguration configuration,

        TplInternalBus internalBus,

        TplExternalBus externalBus)

        : base(configuration, internalBus, externalBus)

    {

    }

    protected override IEnumerable<BackgroundService> CreateBackgroundServices()

    {

        <# for(int i = 0; i < config.WorkerCount; i++) { #>

        yield return new TplBackgroundService(

            new ActionBlock<IApplicationEvent>(

                async e => await ProcessWorker<#= i #>Async(e),

                new ExecutionDataflowBlockOptions 

                { 

                    MaxDegreeOfParallelism = <#= config.MaxParallelism #>,

                    BoundedCapacity = <#= config.Capacity #>

                }),

            "<#= config.Name #>-worker-<#= i #>",

            Logger);

        <# } #>

    }

    <# for(int i = 0; i < config.WorkerCount; i++) { #>

    private async Task ProcessWorker<#= i #>Async(IApplicationEvent @event)

    {

        Logger.LogInformation("Worker <#= i #> in <#= config.Name #> processing event from region <#= config.Region #>");

        

        if (@event is FractalEvent fractalEvent)

        {

            switch (fractalEvent.EventType)

            {

    <# foreach(var handler in config.Handlers) { #>

                case "<#= handler.EventType #>":

                    // <#= handler.Description #>

                    await Task.Delay(<#= handler.ProcessingDelayMs #>);

                    break;

    <# } #>

            }

        }

    }

    <# } #>

    protected override void ConfigureHandlers()

    {

        InternalBus.Subscribe<FractalEvent>(async fractalEvent =>

        {

            await ExternalBus.SendToCellAsync(fractalEvent.TargetCellId, fractalEvent);

        });

    }

}

<#

    }

#>

<#+

// Вспомогательный класс для десериализации

public class CellConfig

{

    public string Name { get; set; }

    public string Region { get; set; }

    public int WorkerCount { get; set; }

    public int MaxParallelism { get; set; }

    public int Capacity { get; set; }

    public List<HandlerConfig> Handlers { get; set; }

}


public class HandlerConfig

{

    public string EventType { get; set; }

    public string Description { get; set; }

    public int ProcessingDelayMs { get; set; }

}

#>

cell-config.json:

json

[

    {

        "Name": "Stratosphere",

        "Region": "north",

        "WorkerCount": 3,

        "MaxParallelism": 4,

        "Capacity": 5000,

        "Handlers": [

            {

                "EventType": "StratosphereDataProcess",

                "Description": "Обработка данных стратосферы",

                "ProcessingDelayMs": 100

            },

            {

                "EventType": "Heartbeat",

                "Description": "Проверка жизнеспособности",

                "ProcessingDelayMs": 10

            }

        ]

    }

]

Как использовать .tt файлы:

В Visual Studio: Правый клик на .tt файл → "Run Custom Tool"

В командной строке: TextTransform.exe ChannelCellTemplate.tt

В CI/CD: Автоматическая генерация перед сборкой

Преимущества T4 для вашей архитектуры:

Массовое создание ячеек: Один шаблон → сотни сгенерированных классов

Конфигурация из JSON: Меняете конфиг → перегенерируете код

Типобезопасность: Генерируется строго типизированный C# код

Шаблонизация поведения: Разные .tt для разных паттернов обработки

Это и есть та самая "фабрика фрактальных ячеек" — пишете конфиг, запускаете шаблон, получаете готовые классы! 🚀

При запуске шаблона с параметрами CellName = "Stratosphere" и Capacity = 5000 сгенерируется:

Где задаются эти параметры ?

Отличный вопрос! Параметры в T4 шаблонах можно задавать несколькими способами, в зависимости от того, как вы запускаете генерацию.

Способ 1: Передача параметров в коде (Runtime T4)

Program.cs или скрипт генерации:

csharp

using Microsoft.VisualStudio.TextTemplating;

using System.CodeDom.Compiler;

// Создаем экземпляр шаблона

var template = new ChannelCellTemplate();

// Создаем сессию и передаем параметры

var session = new Dictionary<string, object>();

session["CellName"] = "Stratosphere";

session["Capacity"] = 5000;

session["BackgroundServiceCount"] = 3;

session["EnableLogging"] = true;

// Инициализируем сессию шаблона

template.Session = session;

// Инициализируем шаблон

template.Initialize();

// Генерируем код

string generatedCode = template.TransformText();

// Сохраняем в файл

File.WriteAllText("Generated/StratosphereChannelCell.generated.cs", generatedCode);

Способ 2: Через файл конфигурации (Design-time T4)

ChannelCellTemplate.tt:

t4

<#@ template debug="true" hostspecific="true" language="C#" #>

<#@ output extension=".generated.cs" #>

<#@ assembly name="System.Core" #>

<#@ assembly name="System.Text.Json" #>

<#@ import namespace="System.IO" #>

<#@ import namespace="System.Text.Json" #>

<#@ import namespace="System.Collections.Generic" #>

<#

    // Читаем параметры из JSON файла

    string configPath = this.Host.ResolvePath("generation-config.json");

    string jsonContent = File.ReadAllText(configPath);

    var configs = JsonSerializer.Deserialize<List<GenerationConfig>>(jsonContent);

    foreach(var config in configs)

    {

        // Используем параметры из конфига

        string cellName = config.CellName;

        int capacity = config.Capacity;

        int workerCount = config.BackgroundServiceCount;     

        // Генерируем код с этими параметрами

        GenerateClass(cellName, capacity, workerCount);

    }

#>

generation-config.json (лежит рядом с .tt файлом):

json

[

    {

        "CellName": "Stratosphere",

        "Capacity": 5000,

        "BackgroundServiceCount": 3,

        "MaxParallelism": 4,

        "Region": "north"

    },

    {

        "CellName": "Troposphere",

        "Capacity": 3000,

        "BackgroundServiceCount": 2,

        "MaxParallelism": 2,

        "Region": "south"

    },

    {

        "CellName": "Mesosphere",

        "Capacity": 7000,

        "BackgroundServiceCount": 5,

        "MaxParallelism": 8,

        "Region": "equator"

    }

]

Способ 3: Параметры из переменных окружения

ChannelCellTemplate.tt:

t4

<#@ template debug="true" hostspecific="true" language="C#" #>

<#@ output extension=".generated.cs" #>

<#@ import namespace="System" #>

<#

    // Читаем параметры из переменных окружения

    string cellName = Environment.GetEnvironmentVariable("CELL_NAME") ?? "DefaultCell";

    int capacity = int.Parse(Environment.GetEnvironmentVariable("CELL_CAPACITY") ?? "1000");

    int workers = int.Parse(Environment.GetEnvironmentVariable("CELL_WORKERS") ?? "2");

    // Генерируем с этими параметрами

#>

Запуск с параметрами:

bash

# Windows

set CELL_NAME=Stratosphere

set CELL_CAPACITY=5000

set CELL_WORKERS=3

TextTransform.exe ChannelCellTemplate.tt

# Linux/Mac

export CELL_NAME=Stratosphere

export CELL_CAPACITY=5000

export CELL_WORKERS=3

mono TextTransform.exe ChannelCellTemplate.tt

Способ 4: Параметры из командной строки

Кастомный скрипт генерации generate-cells.ps1:

powershell

param(

    [string]$CellName = "DefaultCell",

    [int]$Capacity = 1000,

    [int]$Workers = 2

)

# Заменяем параметры в шаблоне

$templateContent = Get-Content "ChannelCellTemplate.tt" -Raw

$templateContent = $templateContent -replace '\$CellName\$', $CellName

$templateContent = $templateContent -replace '\$Capacity\$', $Capacity

$templateContent = $templateContent -replace '\$Workers\$', $Workers

# Сохраняем временный шаблон

$tempTemplate = "Temp_ChannelCellTemplate.tt"

$templateContent | Set-Content $tempTemplate

# Генерируем код

& "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\TextTransform.exe" $tempTemplate

# Переименовываем результат

Move-Item "Temp_ChannelCellTemplate.generated.cs" "$CellNameChannelCell.generated.cs"

Remove-Item $tempTemplate

Запуск:

powershell

# Генерация для Стратосферы

.\generate-cells.ps1 -CellName "Stratosphere" -Capacity 5000 -Workers 3

# Генерация для Тропосферы

.\generate-cells.ps1 -CellName "Troposphere" -Capacity 3000 -Workers 2

# Генерация для Мезосферы

.\generate-cells.ps1 -CellName "Mesosphere" -Capacity 7000 -Workers 5

Способ 5: Использование T4 Toolbox (расширенные параметры)

Установка T4 Toolbox:

xml

<PackageReference Include="T4Toolbox" Version="1.0.0" />

ChannelCellTemplate.tt с T4 Toolbox:

t4

<#@ template language="C#" hostspecific="true" #>

<#@ output extension=".generated.cs" #>

<#@ include file="T4Toolbox.tt" #>

<#

    // Создаем генератор с параметрами

    var generator = new CellGenerator

    {

        CellName = "Stratosphere",

        Capacity = 5000,

        WorkerCount = 3

    }; 

    generator.Run();

#>

Способ 6: Интерактивный ввод (для отладки)

ChannelCellTemplate.tt:

t4

<#@ template debug="true" hostspecific="true" language="C#" #>

<#@ output extension=".generated.cs" #>

<#

    // При debug=true можно использовать интерактивный ввод

    string cellName = "Stratosphere";

    int capacity = 5000;

    int workers = 3;

    if (this.Errors.HasErrors == false)

    {

        // В режиме отладки можно запросить параметры

        Console.Write("Enter cell name: ");

        cellName = Console.ReadLine();

    }

#>

Самый удобный способ для вашего проекта:

Создайте cell-factory.ps1:

powershell

# Конфигурация всех ячеек

$cells = @(

    @{Name="Stratosphere"; Capacity=5000; Workers=3; Region="north"},

    @{Name="Troposphere"; Capacity=3000; Workers=2; Region="south"},

    @{Name="Mesosphere"; Capacity=7000; Workers=5; Region="equator"},

    @{Name="Ionosphere"; Capacity=8000; Workers=4; Region="space"}

)

foreach ($cell in $cells) {

    Write-Host "Generating $($cell.Name) cell..." -ForegroundColor Green

    

    # Создаем временный конфиг для текущей ячейки

    $config = @{

        CellName = $cell.Name

        Capacity = $cell.Capacity

        BackgroundServiceCount = $cell.Workers

        Region = $cell.Region

    }

    $config | ConvertTo-Json | Set-Content "generation-config.json"

    # Запускаем генерацию

    & TextTransform.exe ChannelCellTemplate.tt

    & TextTransform.exe TplCellTemplate.tt

    # Переименовываем результаты

    Move-Item "ChannelCellTemplate.generated.cs" "Generated/$($cell.Name)ChannelCell.cs" -Force

    Move-Item "TplCellTemplate.generated.cs" "Generated/$($cell.Name)TplCell.cs" -Force

}

Write-Host "All cells generated!" -ForegroundColor Cyan

Теперь у вас есть полноценная фабрика для генерации ячеек с разными параметрами! 🏭


 

Комментариев нет:

Отправить комментарий