2026-06-05 12:13:35 +07:00
|
|
|
|
using Microsoft.CodeAnalysis;
|
|
|
|
|
|
using Microsoft.CodeAnalysis.CSharp;
|
|
|
|
|
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
|
|
|
|
|
using Microsoft.CodeAnalysis.Text;
|
|
|
|
|
|
using System.Text;
|
|
|
|
|
|
|
|
|
|
|
|
namespace G;
|
|
|
|
|
|
|
|
|
|
|
|
[Generator]
|
|
|
|
|
|
public class ComplexUnitGenerator : IIncrementalGenerator
|
|
|
|
|
|
{
|
|
|
|
|
|
private const string AttributeName = "ComplexUnitGenerator";
|
|
|
|
|
|
|
|
|
|
|
|
public void Initialize(IncrementalGeneratorInitializationContext context)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 1. Генерируем определение атрибута
|
|
|
|
|
|
context.RegisterPostInitializationOutput(ctx =>
|
|
|
|
|
|
{
|
|
|
|
|
|
string attributeSource = @"
|
|
|
|
|
|
namespace QWERTYkez.Mensura
|
|
|
|
|
|
{
|
|
|
|
|
|
[System.AttributeUsage(System.AttributeTargets.Struct, AllowMultiple = false)]
|
|
|
|
|
|
public sealed class ComplexUnitGeneratorAttribute : System.Attribute
|
|
|
|
|
|
{
|
|
|
|
|
|
public string TypeNameA { get; }
|
|
|
|
|
|
public string TypeNameB { get; }
|
|
|
|
|
|
public string TypeNameZ { get; }
|
|
|
|
|
|
|
|
|
|
|
|
public ComplexUnitGeneratorAttribute(string typeNameA, string typeNameB, string typeNameZ)
|
|
|
|
|
|
{
|
|
|
|
|
|
TypeNameA = typeNameA;
|
|
|
|
|
|
TypeNameB = typeNameB;
|
|
|
|
|
|
TypeNameZ = typeNameZ;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}";
|
|
|
|
|
|
ctx.AddSource(".ComplexUnitGeneratorAttribute.g.cs", SourceText.From(attributeSource, Encoding.UTF8));
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 2. Ищем все readonly partial record struct с этим атрибутом
|
|
|
|
|
|
var structsProvider = context.SyntaxProvider
|
|
|
|
|
|
.CreateSyntaxProvider(
|
|
|
|
|
|
predicate: static (node, _) => IsTargetStruct(node),
|
|
|
|
|
|
transform: static (ctx, _) => GetStructInfo(ctx))
|
|
|
|
|
|
.Where(info => info.HasValue)
|
|
|
|
|
|
.Select((info, _) => info!.Value)
|
|
|
|
|
|
.Collect();
|
|
|
|
|
|
|
|
|
|
|
|
// 3. Регистрируем вывод для каждой найденной структуры
|
|
|
|
|
|
context.RegisterSourceOutput(structsProvider, (spc, structs) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var structInfo in structs)
|
|
|
|
|
|
{
|
|
|
|
|
|
string generatedCode = GeneratePartial(structInfo.TypeName, structInfo.Namespace,
|
|
|
|
|
|
structInfo.TypeNameA, structInfo.TypeNameB, structInfo.TypeNameZ);
|
|
|
|
|
|
spc.AddSource($"{structInfo.TypeName}.g.cs", SourceText.From(generatedCode, Encoding.UTF8));
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static bool IsTargetStruct(SyntaxNode node)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (node is not RecordDeclarationSyntax record)
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
// Должен быть record struct с модификаторами readonly и partial
|
|
|
|
|
|
if (!record.Modifiers.Any(SyntaxKind.ReadOnlyKeyword) ||
|
|
|
|
|
|
!record.Modifiers.Any(SyntaxKind.PartialKeyword) ||
|
|
|
|
|
|
!record.Keyword.IsKind(SyntaxKind.RecordKeyword) ||
|
|
|
|
|
|
!record.ClassOrStructKeyword.IsKind(SyntaxKind.StructKeyword))
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
// Проверяем наличие атрибута [ComplexUnitGenerator] или [ComplexUnitGeneratorAttribute]
|
|
|
|
|
|
foreach (var attrList in record.AttributeLists)
|
|
|
|
|
|
foreach (var attr in attrList.Attributes)
|
|
|
|
|
|
{
|
|
|
|
|
|
string name = attr.Name.ToString();
|
|
|
|
|
|
if (name == AttributeName || name == AttributeName + "Attribute")
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static StructInfo? GetStructInfo(GeneratorSyntaxContext context)
|
|
|
|
|
|
{
|
|
|
|
|
|
var record = (RecordDeclarationSyntax)context.Node;
|
|
|
|
|
|
var semanticModel = context.SemanticModel;
|
|
|
|
|
|
if (semanticModel.GetDeclaredSymbol(record) is not INamedTypeSymbol typeSymbol)
|
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
|
|
string namespaceName = typeSymbol.ContainingNamespace?.ToString() ?? "";
|
|
|
|
|
|
if (string.IsNullOrEmpty(namespaceName))
|
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
|
|
// Извлекаем аргументы атрибута
|
|
|
|
|
|
string typeNameA = null;
|
|
|
|
|
|
string typeNameB = null;
|
|
|
|
|
|
string typeNameZ = null;
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var attrList in record.AttributeLists)
|
|
|
|
|
|
foreach (var attr in attrList.Attributes)
|
|
|
|
|
|
{
|
|
|
|
|
|
string name = attr.Name.ToString();
|
|
|
|
|
|
if (name == AttributeName || name == AttributeName + "Attribute")
|
|
|
|
|
|
{
|
|
|
|
|
|
// Ищем аргументы конструктора
|
|
|
|
|
|
var args = attr.ArgumentList?.Arguments;
|
|
|
|
|
|
if (args.HasValue && args.Value.Count >= 3)
|
|
|
|
|
|
{
|
|
|
|
|
|
typeNameA = GetStringFromExpression(args.Value[0].Expression, semanticModel);
|
|
|
|
|
|
typeNameB = GetStringFromExpression(args.Value[1].Expression, semanticModel);
|
|
|
|
|
|
typeNameZ = GetStringFromExpression(args.Value[2].Expression, semanticModel);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (typeNameA == null || typeNameB == null || typeNameZ == null)
|
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
|
|
return new StructInfo(namespaceName, typeSymbol.Name, typeNameA, typeNameB, typeNameZ);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static string GetStringFromExpression(ExpressionSyntax expr, SemanticModel semanticModel)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Поддерживаем строковые литералы и константы
|
|
|
|
|
|
if (expr is LiteralExpressionSyntax literal && literal.IsKind(SyntaxKind.StringLiteralExpression))
|
|
|
|
|
|
return literal.Token.ValueText;
|
|
|
|
|
|
|
|
|
|
|
|
// Если это доступ к константе, пытаемся вычислить через семантику
|
|
|
|
|
|
var constantValue = semanticModel.GetConstantValue(expr);
|
|
|
|
|
|
if (constantValue.HasValue && constantValue.Value is string s)
|
|
|
|
|
|
return s;
|
|
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static string GeneratePartial(string typeName, string ns, string typeNameA, string typeNameB, string typeNameZ)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Шаблон, который вы вставите сами.
|
|
|
|
|
|
// В нём используйте {typeName}, {ns}, {typeNameA}, {typeNameB}, {typeNameZ}
|
|
|
|
|
|
// Например:
|
|
|
|
|
|
string template = @"
|
2026-06-07 15:54:53 +07:00
|
|
|
|
global using {typeNameZ}Extensions = QWERTYkez.Mensura.Units.{typeNameZ}Extensions;
|
|
|
|
|
|
global using {typeNameZ}Converter = QWERTYkez.Mensura.Units.{typeNameZ}Converter;
|
|
|
|
|
|
global using {typeNameZ} = QWERTYkez.Mensura.Units.{typeNameZ};
|
2026-06-05 12:13:35 +07:00
|
|
|
|
|
|
|
|
|
|
using System.Globalization;
|
|
|
|
|
|
using System.Runtime.Serialization;
|
|
|
|
|
|
|
2026-06-07 15:54:53 +07:00
|
|
|
|
namespace QWERTYkez.Mensura.Units;
|
|
|
|
|
|
|
|
|
|
|
|
public readonly partial record struct {typeNameB}
|
2026-06-05 12:13:35 +07:00
|
|
|
|
{
|
2026-06-07 15:54:53 +07:00
|
|
|
|
public static {typeNameZ} operator /({typeNameA} left, {typeNameB} right) => new(left._Value / right._Value);
|
|
|
|
|
|
public static {typeNameZ} operator /({typeNameA}? left, {typeNameB} right) => new(left.Protected() / right._Value);
|
|
|
|
|
|
public static {typeNameZ} operator /({typeNameA} left, {typeNameB}? right) => new(left._Value / right.Protected());
|
|
|
|
|
|
public static {typeNameZ} operator /({typeNameA}? left, {typeNameB}? right) => new(left.Protected() / right.Protected());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// === Array ===
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameA}[] operator
|
|
|
|
|
|
*({typeNameZ}[] units, {typeNameB} multiplicator) => units.Multiply<{typeNameZ}, {typeNameA}>(multiplicator._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameA}?[] operator
|
|
|
|
|
|
*({typeNameZ}?[] units, {typeNameB} multiplicator) => units.Multiply<{typeNameZ}, {typeNameA}>(multiplicator._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameA}[] operator
|
|
|
|
|
|
*({typeNameB} multiplicator, {typeNameZ}[] units) => units.Multiply<{typeNameZ}, {typeNameA}>(multiplicator._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameA}?[] operator
|
|
|
|
|
|
*({typeNameB} multiplicator, {typeNameZ}?[] units) => units.Multiply<{typeNameZ}, {typeNameA}>(multiplicator._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameA}[] operator *({typeNameZ}[] units, {typeNameB}? multiplicator) =>
|
|
|
|
|
|
multiplicator.HasValue ? units * multiplicator.Value : (units is null ? null! : new {typeNameA}[units.Length]);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameA}?[] operator *({typeNameZ}?[] units, {typeNameB}? multiplicator) =>
|
|
|
|
|
|
multiplicator.HasValue ? units * multiplicator.Value : (units is null ? null! : new {typeNameA}?[units.Length]);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameA}[] operator *({typeNameB}? multiplicator, {typeNameZ}[] units) =>
|
|
|
|
|
|
multiplicator.HasValue ? units * multiplicator.Value : (units is null ? null! : new {typeNameA}[units.Length]);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameA}?[] operator *({typeNameB}? multiplicator, {typeNameZ}?[] units) =>
|
|
|
|
|
|
multiplicator.HasValue ? units * multiplicator.Value : (units is null ? null! : new {typeNameA}?[units.Length]);
|
|
|
|
|
|
|
|
|
|
|
|
// === List<T> ===
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameA}> operator
|
|
|
|
|
|
*(List<{typeNameZ}> units, {typeNameB} multiplicator) => units.Multiply<{typeNameZ}, {typeNameA}>(multiplicator._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameA}?> operator
|
|
|
|
|
|
*(List<{typeNameZ}?> units, {typeNameB} multiplicator) => units.Multiply<{typeNameZ}, {typeNameA}>(multiplicator._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameA}> operator
|
|
|
|
|
|
*({typeNameB} multiplicator, List<{typeNameZ}> units) => units.Multiply<{typeNameZ}, {typeNameA}>(multiplicator._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameA}?> operator
|
|
|
|
|
|
*({typeNameB} multiplicator, List<{typeNameZ}?> units) => units.Multiply<{typeNameZ}, {typeNameA}>(multiplicator._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameA}> operator *(List<{typeNameZ}> units, {typeNameB}? multiplicator) =>
|
|
|
|
|
|
multiplicator.HasValue ? units * multiplicator.Value : (units is null ? null! : new List<{typeNameA}>(units.Count));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameA}?> operator *(List<{typeNameZ}?> units, {typeNameB}? multiplicator) =>
|
|
|
|
|
|
multiplicator.HasValue ? units * multiplicator.Value : (units is null ? null! : new List<{typeNameA}?>(units.Count));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameA}> operator *({typeNameB}? multiplicator, List<{typeNameZ}> units) =>
|
|
|
|
|
|
multiplicator.HasValue ? units * multiplicator.Value : (units is null ? null! : new List<{typeNameA}>(units.Count));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameA}?> operator *({typeNameB}? multiplicator, List<{typeNameZ}?> units) =>
|
|
|
|
|
|
multiplicator.HasValue ? units * multiplicator.Value : (units is null ? null! : new List<{typeNameA}?>(units.Count));
|
|
|
|
|
|
|
|
|
|
|
|
// === IEnumerable<T> ===
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameA}> operator
|
|
|
|
|
|
*(IEnumerable<{typeNameZ}> units, {typeNameB} multiplicator) => units.Multiply<{typeNameZ}, {typeNameA}>(multiplicator._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameA}?> operator
|
|
|
|
|
|
*(IEnumerable<{typeNameZ}?> units, {typeNameB} multiplicator) => units.Multiply<{typeNameZ}, {typeNameA}>(multiplicator._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameA}> operator
|
|
|
|
|
|
*({typeNameB} multiplicator, IEnumerable<{typeNameZ}> units) => units.Multiply<{typeNameZ}, {typeNameA}>(multiplicator._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameA}?> operator
|
|
|
|
|
|
*({typeNameB} multiplicator, IEnumerable<{typeNameZ}?> units) => units.Multiply<{typeNameZ}, {typeNameA}>(multiplicator._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameA}> operator *(IEnumerable<{typeNameZ}> units, {typeNameB}? multiplicator) =>
|
|
|
|
|
|
multiplicator.HasValue ? units * multiplicator.Value : (units is null ? null! : units.Select(u => new {typeNameA}(0d)));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameA}?> operator *(IEnumerable<{typeNameZ}?> units, {typeNameB}? multiplicator) =>
|
|
|
|
|
|
multiplicator.HasValue ? units * multiplicator.Value : (units is null ? null! : units.Select(u => u is null ? ({typeNameA}?)null : new {typeNameA}(0d)));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameA}> operator *({typeNameB}? multiplicator, IEnumerable<{typeNameZ}> units) =>
|
|
|
|
|
|
multiplicator.HasValue ? units * multiplicator.Value : (units is null ? null! : units.Select(u => new {typeNameA}(0d)));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameA}?> operator *({typeNameB}? multiplicator, IEnumerable<{typeNameZ}?> units) =>
|
|
|
|
|
|
multiplicator.HasValue ? units * multiplicator.Value : (units is null ? null! : units.Select(u => u is null ? ({typeNameA}?)null : new {typeNameA}(0d)));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// === Array ===
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameZ}[] operator
|
|
|
|
|
|
/({typeNameA}[] units, {typeNameB} divisor) => units.Divide<{typeNameA}, {typeNameZ}>(divisor._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameZ}?[] operator
|
|
|
|
|
|
/({typeNameA}?[] units, {typeNameB} divisor) => units.Divide<{typeNameA}, {typeNameZ}>(divisor._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameZ}[] operator
|
|
|
|
|
|
/({typeNameB} dividend, {typeNameA}[] units) => dividend._Value.Divide<{typeNameA}, {typeNameZ}>(units);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameZ}?[] operator
|
|
|
|
|
|
/({typeNameB} dividend, {typeNameA}?[] units) => dividend._Value.Divide<{typeNameA}, {typeNameZ}>(units);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameZ}[] operator /({typeNameA}[] units, {typeNameB}? divisor) =>
|
|
|
|
|
|
divisor.HasValue ? units / divisor.Value : (units is null ? null! : new {typeNameZ}[units.Length]);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameZ}?[] operator /({typeNameA}?[] units, {typeNameB}? divisor) =>
|
|
|
|
|
|
divisor.HasValue ? units / divisor.Value : (units is null ? null! : new {typeNameZ}?[units.Length]);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameZ}[] operator /({typeNameB}? dividend, {typeNameA}[] units) =>
|
|
|
|
|
|
dividend.HasValue ? units / dividend.Value : (units is null ? null! : new {typeNameZ}[units.Length]);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameZ}?[] operator /({typeNameB}? dividend, {typeNameA}?[] units) =>
|
|
|
|
|
|
dividend.HasValue ? units / dividend.Value : (units is null ? null! : new {typeNameZ}?[units.Length]);
|
|
|
|
|
|
|
|
|
|
|
|
// === List<T> ===
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameZ}> operator
|
|
|
|
|
|
/(List<{typeNameA}> units, {typeNameB} divisor) => units.Divide<{typeNameA}, {typeNameZ}>(divisor._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameZ}?> operator
|
|
|
|
|
|
/(List<{typeNameA}?> units, {typeNameB} divisor) => units.Divide<{typeNameA}, {typeNameZ}>(divisor._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameZ}> operator
|
|
|
|
|
|
/({typeNameB} dividend, List<{typeNameA}> units) => dividend._Value.Divide<{typeNameA}, {typeNameZ}>(units);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameZ}?> operator
|
|
|
|
|
|
/({typeNameB} dividend, List<{typeNameA}?> units) => dividend._Value.Divide<{typeNameA}, {typeNameZ}>(units);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameZ}> operator /(List<{typeNameA}> units, {typeNameB}? divisor) =>
|
|
|
|
|
|
divisor.HasValue ? units / divisor.Value : (units is null ? null! : new List<{typeNameZ}>(units.Count));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameZ}?> operator /(List<{typeNameA}?> units, {typeNameB}? divisor) =>
|
|
|
|
|
|
divisor.HasValue ? units / divisor.Value : (units is null ? null! : new List<{typeNameZ}?>(units.Count));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameZ}> operator /({typeNameB}? dividend, List<{typeNameA}> units) =>
|
|
|
|
|
|
dividend.HasValue ? units / dividend.Value : (units is null ? null! : new List<{typeNameZ}>(units.Count));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameZ}?> operator /({typeNameB}? dividend, List<{typeNameA}?> units) =>
|
|
|
|
|
|
dividend.HasValue ? units / dividend.Value : (units is null ? null! : new List<{typeNameZ}?>(units.Count));
|
|
|
|
|
|
|
|
|
|
|
|
// === IEnumerable<T> ===
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameZ}> operator
|
|
|
|
|
|
/(IEnumerable<{typeNameA}> units, {typeNameB} divisor) => units.Divide<{typeNameA}, {typeNameZ}>(divisor._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameZ}?> operator
|
|
|
|
|
|
/(IEnumerable<{typeNameA}?> units, {typeNameB} divisor) => units.Divide<{typeNameA}, {typeNameZ}>(divisor._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameZ}> operator
|
|
|
|
|
|
/({typeNameB} dividend, IEnumerable<{typeNameA}> units) => dividend._Value.Divide<{typeNameA}, {typeNameZ}>(units);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameZ}?> operator
|
|
|
|
|
|
/({typeNameB} dividend, IEnumerable<{typeNameA}?> units) => dividend._Value.Divide<{typeNameA}, {typeNameZ}>(units);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameZ}> operator /(IEnumerable<{typeNameA}> units, {typeNameB}? divisor) =>
|
|
|
|
|
|
divisor.HasValue ? units / divisor.Value : (units is null ? null! : units.Select(u => new {typeNameZ}(0d)));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameZ}?> operator /(IEnumerable<{typeNameA}?> units, {typeNameB}? divisor) =>
|
|
|
|
|
|
divisor.HasValue ? units / divisor.Value : (units is null ? null! : units.Select(u => u is null ? ({typeNameZ}?)null : new {typeNameZ}(0d)));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameZ}> operator /({typeNameB}? dividend, IEnumerable<{typeNameA}> units) =>
|
|
|
|
|
|
dividend.HasValue ? units / dividend.Value : (units is null ? null! : units.Select(u => new {typeNameZ}(0d)));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameZ}?> operator /({typeNameB}? dividend, IEnumerable<{typeNameA}?> units) =>
|
|
|
|
|
|
dividend.HasValue ? units / dividend.Value : (units is null ? null! : units.Select(u => u is null ? ({typeNameZ}?)null : new {typeNameZ}(0d)));
|
|
|
|
|
|
}
|
|
|
|
|
|
public readonly partial record struct {typeNameA}
|
|
|
|
|
|
{
|
|
|
|
|
|
// === Array ===
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameB}[] operator
|
|
|
|
|
|
/({typeNameZ}[] units, {typeNameA} divisor) => units.Divide<{typeNameZ}, {typeNameB}>(divisor._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameB}?[] operator
|
|
|
|
|
|
/({typeNameZ}?[] units, {typeNameA} divisor) => units.Divide<{typeNameZ}, {typeNameB}>(divisor._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameB}[] operator
|
|
|
|
|
|
/({typeNameA} dividend, {typeNameZ}[] units) => dividend._Value.Divide<{typeNameZ}, {typeNameB}>(units);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameB}?[] operator
|
|
|
|
|
|
/({typeNameA} dividend, {typeNameZ}?[] units) => dividend._Value.Divide<{typeNameZ}, {typeNameB}>(units);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameB}[] operator /({typeNameZ}[] units, {typeNameA}? divisor) =>
|
|
|
|
|
|
divisor.HasValue ? units / divisor.Value : (units is null ? null! : new {typeNameB}[units.Length]);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameB}?[] operator /({typeNameZ}?[] units, {typeNameA}? divisor) =>
|
|
|
|
|
|
divisor.HasValue ? units / divisor.Value : (units is null ? null! : new {typeNameB}?[units.Length]);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameB}[] operator /({typeNameA}? dividend, {typeNameZ}[] units) =>
|
|
|
|
|
|
dividend.HasValue ? units / dividend.Value : (units is null ? null! : new {typeNameB}[units.Length]);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameB}?[] operator /({typeNameA}? dividend, {typeNameZ}?[] units) =>
|
|
|
|
|
|
dividend.HasValue ? units / dividend.Value : (units is null ? null! : new {typeNameB}?[units.Length]);
|
|
|
|
|
|
|
|
|
|
|
|
// === List<T> ===
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameB}> operator
|
|
|
|
|
|
/(List<{typeNameZ}> units, {typeNameA} divisor) => units.Divide<{typeNameZ}, {typeNameB}>(divisor._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameB}?> operator
|
|
|
|
|
|
/(List<{typeNameZ}?> units, {typeNameA} divisor) => units.Divide<{typeNameZ}, {typeNameB}>(divisor._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameB}> operator
|
|
|
|
|
|
/({typeNameA} dividend, List<{typeNameZ}> units) => dividend._Value.Divide<{typeNameZ}, {typeNameB}>(units);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameB}?> operator
|
|
|
|
|
|
/({typeNameA} dividend, List<{typeNameZ}?> units) => dividend._Value.Divide<{typeNameZ}, {typeNameB}>(units);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameB}> operator /(List<{typeNameZ}> units, {typeNameA}? divisor) =>
|
|
|
|
|
|
divisor.HasValue ? units / divisor.Value : (units is null ? null! : new List<{typeNameB}>(units.Count));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameB}?> operator /(List<{typeNameZ}?> units, {typeNameA}? divisor) =>
|
|
|
|
|
|
divisor.HasValue ? units / divisor.Value : (units is null ? null! : new List<{typeNameB}?>(units.Count));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameB}> operator /({typeNameA}? dividend, List<{typeNameZ}> units) =>
|
|
|
|
|
|
dividend.HasValue ? units / dividend.Value : (units is null ? null! : new List<{typeNameB}>(units.Count));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameB}?> operator /({typeNameA}? dividend, List<{typeNameZ}?> units) =>
|
|
|
|
|
|
dividend.HasValue ? units / dividend.Value : (units is null ? null! : new List<{typeNameB}?>(units.Count));
|
|
|
|
|
|
|
|
|
|
|
|
// === IEnumerable<T> ===
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameB}> operator
|
|
|
|
|
|
/(IEnumerable<{typeNameZ}> units, {typeNameA} divisor) => units.Divide<{typeNameZ}, {typeNameB}>(divisor._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameB}?> operator
|
|
|
|
|
|
/(IEnumerable<{typeNameZ}?> units, {typeNameA} divisor) => units.Divide<{typeNameZ}, {typeNameB}>(divisor._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameB}> operator
|
|
|
|
|
|
/({typeNameA} dividend, IEnumerable<{typeNameZ}> units) => dividend._Value.Divide<{typeNameZ}, {typeNameB}>(units);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameB}?> operator
|
|
|
|
|
|
/({typeNameA} dividend, IEnumerable<{typeNameZ}?> units) => dividend._Value.Divide<{typeNameZ}, {typeNameB}>(units);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameB}> operator /(IEnumerable<{typeNameZ}> units, {typeNameA}? divisor) =>
|
|
|
|
|
|
divisor.HasValue ? units / divisor.Value : (units is null ? null! : units.Select(u => new {typeNameB}(0d)));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameB}?> operator /(IEnumerable<{typeNameZ}?> units, {typeNameA}? divisor) =>
|
|
|
|
|
|
divisor.HasValue ? units / divisor.Value : (units is null ? null! : units.Select(u => u is null ? ({typeNameB}?)null : new {typeNameB}(0d)));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameB}> operator /({typeNameA}? dividend, IEnumerable<{typeNameZ}> units) =>
|
|
|
|
|
|
dividend.HasValue ? units / dividend.Value : (units is null ? null! : units.Select(u => new {typeNameB}(0d)));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameB}?> operator /({typeNameA}? dividend, IEnumerable<{typeNameZ}?> units) =>
|
|
|
|
|
|
dividend.HasValue ? units / dividend.Value : (units is null ? null! : units.Select(u => u is null ? ({typeNameB}?)null : new {typeNameB}(0d)));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// === Array ===
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameZ}[] operator
|
|
|
|
|
|
/({typeNameB}[] units, {typeNameA} divisor) => units.Divide<{typeNameB}, {typeNameZ}>(divisor._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameZ}?[] operator
|
|
|
|
|
|
/({typeNameB}?[] units, {typeNameA} divisor) => units.Divide<{typeNameB}, {typeNameZ}>(divisor._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameZ}[] operator
|
|
|
|
|
|
/({typeNameA} dividend, {typeNameB}[] units) => dividend._Value.Divide<{typeNameB}, {typeNameZ}>(units);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameZ}?[] operator
|
|
|
|
|
|
/({typeNameA} dividend, {typeNameB}?[] units) => dividend._Value.Divide<{typeNameB}, {typeNameZ}>(units);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameZ}[] operator /({typeNameB}[] units, {typeNameA}? divisor) =>
|
|
|
|
|
|
divisor.HasValue ? units / divisor.Value : (units is null ? null! : new {typeNameZ}[units.Length]);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameZ}?[] operator /({typeNameB}?[] units, {typeNameA}? divisor) =>
|
|
|
|
|
|
divisor.HasValue ? units / divisor.Value : (units is null ? null! : new {typeNameZ}?[units.Length]);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameZ}[] operator /({typeNameA}? dividend, {typeNameB}[] units) =>
|
|
|
|
|
|
dividend.HasValue ? units / dividend.Value : (units is null ? null! : new {typeNameZ}[units.Length]);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameZ}?[] operator /({typeNameA}? dividend, {typeNameB}?[] units) =>
|
|
|
|
|
|
dividend.HasValue ? units / dividend.Value : (units is null ? null! : new {typeNameZ}?[units.Length]);
|
|
|
|
|
|
|
|
|
|
|
|
// === List<T> ===
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameZ}> operator
|
|
|
|
|
|
/(List<{typeNameB}> units, {typeNameA} divisor) => units.Divide<{typeNameB}, {typeNameZ}>(divisor._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameZ}?> operator
|
|
|
|
|
|
/(List<{typeNameB}?> units, {typeNameA} divisor) => units.Divide<{typeNameB}, {typeNameZ}>(divisor._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameZ}> operator
|
|
|
|
|
|
/({typeNameA} dividend, List<{typeNameB}> units) => dividend._Value.Divide<{typeNameB}, {typeNameZ}>(units);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameZ}?> operator
|
|
|
|
|
|
/({typeNameA} dividend, List<{typeNameB}?> units) => dividend._Value.Divide<{typeNameB}, {typeNameZ}>(units);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameZ}> operator /(List<{typeNameB}> units, {typeNameA}? divisor) =>
|
|
|
|
|
|
divisor.HasValue ? units / divisor.Value : (units is null ? null! : new List<{typeNameZ}>(units.Count));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameZ}?> operator /(List<{typeNameB}?> units, {typeNameA}? divisor) =>
|
|
|
|
|
|
divisor.HasValue ? units / divisor.Value : (units is null ? null! : new List<{typeNameZ}?>(units.Count));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameZ}> operator /({typeNameA}? dividend, List<{typeNameB}> units) =>
|
|
|
|
|
|
dividend.HasValue ? units / dividend.Value : (units is null ? null! : new List<{typeNameZ}>(units.Count));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameZ}?> operator /({typeNameA}? dividend, List<{typeNameB}?> units) =>
|
|
|
|
|
|
dividend.HasValue ? units / dividend.Value : (units is null ? null! : new List<{typeNameZ}?>(units.Count));
|
|
|
|
|
|
|
|
|
|
|
|
// === IEnumerable<T> ===
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameZ}> operator
|
|
|
|
|
|
/(IEnumerable<{typeNameB}> units, {typeNameA} divisor) => units.Divide<{typeNameB}, {typeNameZ}>(divisor._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameZ}?> operator
|
|
|
|
|
|
/(IEnumerable<{typeNameB}?> units, {typeNameA} divisor) => units.Divide<{typeNameB}, {typeNameZ}>(divisor._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameZ}> operator
|
|
|
|
|
|
/({typeNameA} dividend, IEnumerable<{typeNameB}> units) => dividend._Value.Divide<{typeNameB}, {typeNameZ}>(units);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameZ}?> operator
|
|
|
|
|
|
/({typeNameA} dividend, IEnumerable<{typeNameB}?> units) => dividend._Value.Divide<{typeNameB}, {typeNameZ}>(units);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameZ}> operator /(IEnumerable<{typeNameB}> units, {typeNameA}? divisor) =>
|
|
|
|
|
|
divisor.HasValue ? units / divisor.Value : (units is null ? null! : units.Select(u => new {typeNameZ}(0d)));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameZ}?> operator /(IEnumerable<{typeNameB}?> units, {typeNameA}? divisor) =>
|
|
|
|
|
|
divisor.HasValue ? units / divisor.Value : (units is null ? null! : units.Select(u => u is null ? ({typeNameZ}?)null : new {typeNameZ}(0d)));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameZ}> operator /({typeNameA}? dividend, IEnumerable<{typeNameB}> units) =>
|
|
|
|
|
|
dividend.HasValue ? units / dividend.Value : (units is null ? null! : units.Select(u => new {typeNameZ}(0d)));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameZ}?> operator /({typeNameA}? dividend, IEnumerable<{typeNameB}?> units) =>
|
|
|
|
|
|
dividend.HasValue ? units / dividend.Value : (units is null ? null! : units.Select(u => u is null ? ({typeNameZ}?)null : new {typeNameZ}(0d)));
|
2026-06-05 12:13:35 +07:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-07 15:54:53 +07:00
|
|
|
|
[JsonConverter(typeof({typeNameZ}Converter))]
|
|
|
|
|
|
public readonly partial record struct {typeNameZ} : IMensuraUnit<{typeNameZ}>, IEquatable<{typeNameZ}>, IMensuraUnit
|
2026-06-05 12:13:35 +07:00
|
|
|
|
{
|
|
|
|
|
|
|
2026-06-07 15:54:53 +07:00
|
|
|
|
[JsonInclude, DataMember, JsonPropertyName(""v""), Obsolete] // для JSON / EF на случай сбоев, если пробелма с _Value
|
|
|
|
|
|
internal double Value { get => _Value; init => _Value = value; }
|
|
|
|
|
|
internal readonly double _Value;
|
|
|
|
|
|
internal {typeNameZ}(double value) => _Value = value;
|
2026-06-05 12:13:35 +07:00
|
|
|
|
|
|
|
|
|
|
|
2026-06-07 15:54:53 +07:00
|
|
|
|
[NotMapped, JsonIgnore] internal {typeNameA} PerValue
|
|
|
|
|
|
{ get => ({typeNameA})_Value; init => _Value = (double)value; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[JsonIgnore, IgnoreDataMember] public bool IsPositive => _Value >= 0;
|
|
|
|
|
|
[JsonIgnore, IgnoreDataMember] public bool IsGreaterThanZero => _Value > 0;
|
|
|
|
|
|
[JsonIgnore, IgnoreDataMember] public bool IsNegative => double.IsNegative(_Value);
|
|
|
|
|
|
[JsonIgnore, IgnoreDataMember] public bool IsZero => _Value == 0;
|
|
|
|
|
|
[JsonIgnore, IgnoreDataMember] public bool IsNaN => double.IsNaN(_Value);
|
|
|
|
|
|
[JsonIgnore, IgnoreDataMember] public bool IsFinite => double.IsFinite(_Value);
|
|
|
|
|
|
[JsonIgnore, IgnoreDataMember] public bool IsInfinity => double.IsInfinity(_Value);
|
|
|
|
|
|
[JsonIgnore, IgnoreDataMember] public bool IsPositiveInfinity => double.IsPositiveInfinity(_Value);
|
|
|
|
|
|
[JsonIgnore, IgnoreDataMember] public bool IsNegativeInfinity => double.IsNegativeInfinity(_Value);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static {typeNameA} operator *({typeNameZ} left, {typeNameB} right) => new(left._Value * right._Value);
|
|
|
|
|
|
public static {typeNameA} operator *({typeNameZ}? left, {typeNameB} right) => new(left.Protected() * right._Value);
|
|
|
|
|
|
public static {typeNameA} operator *({typeNameZ} left, {typeNameB}? right) => new(left._Value * right.Protected());
|
|
|
|
|
|
public static {typeNameA} operator *({typeNameZ}? left, {typeNameB}? right) => new(left.Protected() * right.Protected());
|
|
|
|
|
|
|
|
|
|
|
|
public static {typeNameA} operator *({typeNameB} left, {typeNameZ} right) => new(right._Value * left._Value);
|
|
|
|
|
|
public static {typeNameA} operator *({typeNameB}? left, {typeNameZ} right) => new(right._Value * left.Protected());
|
|
|
|
|
|
public static {typeNameA} operator *({typeNameB} left, {typeNameZ}? right) => new(right.Protected() * left._Value);
|
|
|
|
|
|
public static {typeNameA} operator *({typeNameB}? left, {typeNameZ}? right) => new(right.Protected() * left.Protected());
|
|
|
|
|
|
|
|
|
|
|
|
public static {typeNameB} operator /({typeNameA} left, {typeNameZ} right) => new(left._Value / right._Value);
|
|
|
|
|
|
public static {typeNameB} operator /({typeNameA}? left, {typeNameZ} right) => new(left.Protected() / right._Value);
|
|
|
|
|
|
public static {typeNameB} operator /({typeNameA} left, {typeNameZ}? right) => new(left._Value / right.Protected());
|
|
|
|
|
|
public static {typeNameB} operator /({typeNameA}? left, {typeNameZ}? right) => new(left.Protected() / right.Protected());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// === Array ===
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameA}[] operator
|
|
|
|
|
|
*({typeNameB}[] units, {typeNameZ} multiplicator) => units.Multiply<{typeNameB}, {typeNameA}>(multiplicator._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameA}?[] operator
|
|
|
|
|
|
*({typeNameB}?[] units, {typeNameZ} multiplicator) => units.Multiply<{typeNameB}, {typeNameA}>(multiplicator._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameA}[] operator
|
|
|
|
|
|
*({typeNameZ} multiplicator, {typeNameB}[] units) => units.Multiply<{typeNameB}, {typeNameA}>(multiplicator._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameA}?[] operator
|
|
|
|
|
|
*({typeNameZ} multiplicator, {typeNameB}?[] units) => units.Multiply<{typeNameB}, {typeNameA}>(multiplicator._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameA}[] operator *({typeNameB}[] units, {typeNameZ}? multiplicator) =>
|
|
|
|
|
|
multiplicator.HasValue ? units * multiplicator.Value : (units is null ? null! : new {typeNameA}[units.Length]);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameA}?[] operator *({typeNameB}?[] units, {typeNameZ}? multiplicator) =>
|
|
|
|
|
|
multiplicator.HasValue ? units * multiplicator.Value : (units is null ? null! : new {typeNameA}?[units.Length]);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameA}[] operator *({typeNameZ}? multiplicator, {typeNameB}[] units) =>
|
|
|
|
|
|
multiplicator.HasValue ? units * multiplicator.Value : (units is null ? null! : new {typeNameA}[units.Length]);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameA}?[] operator *({typeNameZ}? multiplicator, {typeNameB}?[] units) =>
|
|
|
|
|
|
multiplicator.HasValue ? units * multiplicator.Value : (units is null ? null! : new {typeNameA}?[units.Length]);
|
|
|
|
|
|
|
|
|
|
|
|
// === List<T> ===
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameA}> operator
|
|
|
|
|
|
*(List<{typeNameB}> units, {typeNameZ} multiplicator) => units.Multiply<{typeNameB}, {typeNameA}>(multiplicator._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameA}?> operator
|
|
|
|
|
|
*(List<{typeNameB}?> units, {typeNameZ} multiplicator) => units.Multiply<{typeNameB}, {typeNameA}>(multiplicator._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameA}> operator
|
|
|
|
|
|
*({typeNameZ} multiplicator, List<{typeNameB}> units) => units.Multiply<{typeNameB}, {typeNameA}>(multiplicator._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameA}?> operator
|
|
|
|
|
|
*({typeNameZ} multiplicator, List<{typeNameB}?> units) => units.Multiply<{typeNameB}, {typeNameA}>(multiplicator._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameA}> operator *(List<{typeNameB}> units, {typeNameZ}? multiplicator) =>
|
|
|
|
|
|
multiplicator.HasValue ? units * multiplicator.Value : (units is null ? null! : new List<{typeNameA}>(units.Count));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameA}?> operator *(List<{typeNameB}?> units, {typeNameZ}? multiplicator) =>
|
|
|
|
|
|
multiplicator.HasValue ? units * multiplicator.Value : (units is null ? null! : new List<{typeNameA}?>(units.Count));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameA}> operator *({typeNameZ}? multiplicator, List<{typeNameB}> units) =>
|
|
|
|
|
|
multiplicator.HasValue ? units * multiplicator.Value : (units is null ? null! : new List<{typeNameA}>(units.Count));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameA}?> operator *({typeNameZ}? multiplicator, List<{typeNameB}?> units) =>
|
|
|
|
|
|
multiplicator.HasValue ? units * multiplicator.Value : (units is null ? null! : new List<{typeNameA}?>(units.Count));
|
|
|
|
|
|
|
|
|
|
|
|
// === IEnumerable<T> ===
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameA}> operator
|
|
|
|
|
|
*(IEnumerable<{typeNameB}> units, {typeNameZ} multiplicator) => units.Multiply<{typeNameB}, {typeNameA}>(multiplicator._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameA}?> operator
|
|
|
|
|
|
*(IEnumerable<{typeNameB}?> units, {typeNameZ} multiplicator) => units.Multiply<{typeNameB}, {typeNameA}>(multiplicator._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameA}> operator
|
|
|
|
|
|
*({typeNameZ} multiplicator, IEnumerable<{typeNameB}> units) => units.Multiply<{typeNameB}, {typeNameA}>(multiplicator._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameA}?> operator
|
|
|
|
|
|
*({typeNameZ} multiplicator, IEnumerable<{typeNameB}?> units) => units.Multiply<{typeNameB}, {typeNameA}>(multiplicator._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameA}> operator *(IEnumerable<{typeNameB}> units, {typeNameZ}? multiplicator) =>
|
|
|
|
|
|
multiplicator.HasValue ? units * multiplicator.Value : (units is null ? null! : units.Select(u => new {typeNameA}(0d)));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameA}?> operator *(IEnumerable<{typeNameB}?> units, {typeNameZ}? multiplicator) =>
|
|
|
|
|
|
multiplicator.HasValue ? units * multiplicator.Value : (units is null ? null! : units.Select(u => u is null ? ({typeNameA}?)null : new {typeNameA}(0d)));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameA}> operator *({typeNameZ}? multiplicator, IEnumerable<{typeNameB}> units) =>
|
|
|
|
|
|
multiplicator.HasValue ? units * multiplicator.Value : (units is null ? null! : units.Select(u => new {typeNameA}(0d)));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameA}?> operator *({typeNameZ}? multiplicator, IEnumerable<{typeNameB}?> units) =>
|
|
|
|
|
|
multiplicator.HasValue ? units * multiplicator.Value : (units is null ? null! : units.Select(u => u is null ? ({typeNameA}?)null : new {typeNameA}(0d)));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// === Array ===
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameB}[] operator
|
|
|
|
|
|
/({typeNameA}[] units, {typeNameZ} divisor) => units.Divide<{typeNameA}, {typeNameB}>(divisor._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameB}?[] operator
|
|
|
|
|
|
/({typeNameA}?[] units, {typeNameZ} divisor) => units.Divide<{typeNameA}, {typeNameB}>(divisor._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameB}[] operator
|
|
|
|
|
|
/({typeNameZ} dividend, {typeNameA}[] units) => dividend._Value.Divide<{typeNameA}, {typeNameB}>(units);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameB}?[] operator
|
|
|
|
|
|
/({typeNameZ} dividend, {typeNameA}?[] units) => dividend._Value.Divide<{typeNameA}, {typeNameB}>(units);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameB}[] operator /({typeNameA}[] units, {typeNameZ}? divisor) =>
|
|
|
|
|
|
divisor.HasValue ? units / divisor.Value : (units is null ? null! : new {typeNameB}[units.Length]);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameB}?[] operator /({typeNameA}?[] units, {typeNameZ}? divisor) =>
|
|
|
|
|
|
divisor.HasValue ? units / divisor.Value : (units is null ? null! : new {typeNameB}?[units.Length]);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameB}[] operator /({typeNameZ}? dividend, {typeNameA}[] units) =>
|
|
|
|
|
|
dividend.HasValue ? units / dividend.Value : (units is null ? null! : new {typeNameB}[units.Length]);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static {typeNameB}?[] operator /({typeNameZ}? dividend, {typeNameA}?[] units) =>
|
|
|
|
|
|
dividend.HasValue ? units / dividend.Value : (units is null ? null! : new {typeNameB}?[units.Length]);
|
|
|
|
|
|
|
|
|
|
|
|
// === List<T> ===
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameB}> operator
|
|
|
|
|
|
/(List<{typeNameA}> units, {typeNameZ} divisor) => units.Divide<{typeNameA}, {typeNameB}>(divisor._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameB}?> operator
|
|
|
|
|
|
/(List<{typeNameA}?> units, {typeNameZ} divisor) => units.Divide<{typeNameA}, {typeNameB}>(divisor._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameB}> operator
|
|
|
|
|
|
/({typeNameZ} dividend, List<{typeNameA}> units) => dividend._Value.Divide<{typeNameA}, {typeNameB}>(units);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameB}?> operator
|
|
|
|
|
|
/({typeNameZ} dividend, List<{typeNameA}?> units) => dividend._Value.Divide<{typeNameA}, {typeNameB}>(units);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameB}> operator /(List<{typeNameA}> units, {typeNameZ}? divisor) =>
|
|
|
|
|
|
divisor.HasValue ? units / divisor.Value : (units is null ? null! : new List<{typeNameB}>(units.Count));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameB}?> operator /(List<{typeNameA}?> units, {typeNameZ}? divisor) =>
|
|
|
|
|
|
divisor.HasValue ? units / divisor.Value : (units is null ? null! : new List<{typeNameB}?>(units.Count));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameB}> operator /({typeNameZ}? dividend, List<{typeNameA}> units) =>
|
|
|
|
|
|
dividend.HasValue ? units / dividend.Value : (units is null ? null! : new List<{typeNameB}>(units.Count));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeNameB}?> operator /({typeNameZ}? dividend, List<{typeNameA}?> units) =>
|
|
|
|
|
|
dividend.HasValue ? units / dividend.Value : (units is null ? null! : new List<{typeNameB}?>(units.Count));
|
|
|
|
|
|
|
|
|
|
|
|
// === IEnumerable<T> ===
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameB}> operator
|
|
|
|
|
|
/(IEnumerable<{typeNameA}> units, {typeNameZ} divisor) => units.Divide<{typeNameA}, {typeNameB}>(divisor._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameB}?> operator
|
|
|
|
|
|
/(IEnumerable<{typeNameA}?> units, {typeNameZ} divisor) => units.Divide<{typeNameA}, {typeNameB}>(divisor._Value);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameB}> operator
|
|
|
|
|
|
/({typeNameZ} dividend, IEnumerable<{typeNameA}> units) => dividend._Value.Divide<{typeNameA}, {typeNameB}>(units);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameB}?> operator
|
|
|
|
|
|
/({typeNameZ} dividend, IEnumerable<{typeNameA}?> units) => dividend._Value.Divide<{typeNameA}, {typeNameB}>(units);
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameB}> operator /(IEnumerable<{typeNameA}> units, {typeNameZ}? divisor) =>
|
|
|
|
|
|
divisor.HasValue ? units / divisor.Value : (units is null ? null! : units.Select(u => new {typeNameB}(0d)));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameB}?> operator /(IEnumerable<{typeNameA}?> units, {typeNameZ}? divisor) =>
|
|
|
|
|
|
divisor.HasValue ? units / divisor.Value : (units is null ? null! : units.Select(u => u is null ? ({typeNameB}?)null : new {typeNameB}(0d)));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameB}> operator /({typeNameZ}? dividend, IEnumerable<{typeNameA}> units) =>
|
|
|
|
|
|
dividend.HasValue ? units / dividend.Value : (units is null ? null! : units.Select(u => new {typeNameB}(0d)));
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<{typeNameB}?> operator /({typeNameZ}? dividend, IEnumerable<{typeNameA}?> units) =>
|
|
|
|
|
|
dividend.HasValue ? units / dividend.Value : (units is null ? null! : units.Select(u => u is null ? ({typeNameB}?)null : new {typeNameB}(0d)));
|
|
|
|
|
|
}
|
2026-06-05 12:13:35 +07:00
|
|
|
|
|
2026-06-07 15:54:53 +07:00
|
|
|
|
internal static class {typeNameZ}Extensions
|
|
|
|
|
|
{
|
|
|
|
|
|
public static double Protected(this {typeNameZ}? unit) => unit is null ? 0d : unit.Value._Value;
|
|
|
|
|
|
internal static double ToDouble(this {typeNameB}? unit) => unit?._Value ?? 0d;
|
|
|
|
|
|
}
|
2026-06-05 12:13:35 +07:00
|
|
|
|
|
2026-06-07 15:54:53 +07:00
|
|
|
|
public class {typeNameZ}Converter : JsonConverter<{typeNameZ}>
|
|
|
|
|
|
{
|
|
|
|
|
|
// Используем инвариантную культуру, чтобы разделителем всегда была точка (10.5, а не 10,5)
|
|
|
|
|
|
private static readonly CultureInfo Culture = CultureInfo.InvariantCulture;
|
|
|
|
|
|
|
|
|
|
|
|
public override {typeNameZ} Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
2026-06-05 12:13:35 +07:00
|
|
|
|
{
|
2026-06-07 15:54:53 +07:00
|
|
|
|
double double_Value;
|
2026-06-05 12:13:35 +07:00
|
|
|
|
|
2026-06-07 15:54:53 +07:00
|
|
|
|
if (reader.TokenType == JsonTokenType.String)
|
2026-06-05 12:13:35 +07:00
|
|
|
|
{
|
2026-06-07 15:54:53 +07:00
|
|
|
|
// Безопасно парсим double из строки с поддержкой точки как разделителя
|
|
|
|
|
|
if (!double.TryParse(reader.GetString(), NumberStyles.Float, Culture, out double_Value))
|
2026-06-05 12:13:35 +07:00
|
|
|
|
{
|
2026-06-07 15:54:53 +07:00
|
|
|
|
throw new JsonException($""Не удалось преобразовать строковое значение в double для метрики {nameof({typeNameZ})}."");
|
2026-06-05 12:13:35 +07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-06-07 15:54:53 +07:00
|
|
|
|
else
|
2026-06-05 12:13:35 +07:00
|
|
|
|
{
|
2026-06-07 15:54:53 +07:00
|
|
|
|
// Прямое быстрое чтение числа из JSON
|
|
|
|
|
|
double_Value = reader.GetDouble();
|
2026-06-05 12:13:35 +07:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-07 15:54:53 +07:00
|
|
|
|
return new(double_Value);
|
|
|
|
|
|
}
|
2026-06-05 12:13:35 +07:00
|
|
|
|
|
2026-06-07 15:54:53 +07:00
|
|
|
|
public override void Write(Utf8JsonWriter writer, {typeNameZ} value, JsonSerializerOptions options)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Записываем число напрямую в байтовый буфер без выделения памяти под строки
|
|
|
|
|
|
writer.WriteNumberValue(value._Value);
|
|
|
|
|
|
}
|
2026-06-05 12:13:35 +07:00
|
|
|
|
|
2026-06-07 15:54:53 +07:00
|
|
|
|
public override void WriteAsPropertyName(Utf8JsonWriter writer, {typeNameZ} value, JsonSerializerOptions options)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Ключи JSON-объектов всегда должны быть строками.
|
|
|
|
|
|
// Форматируем double в строку с точкой, чтобы другие сервисы экосистемы прочитали её корректно.
|
|
|
|
|
|
// Формат ""R"" (Round-trip) гарантирует, что число не потеряет точность при обратном парсинге.
|
|
|
|
|
|
writer.WritePropertyName(value._Value.ToString(""R"", Culture));
|
|
|
|
|
|
}
|
2026-06-05 12:13:35 +07:00
|
|
|
|
|
2026-06-07 15:54:53 +07:00
|
|
|
|
public override {typeNameZ} ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
|
|
|
|
|
{
|
|
|
|
|
|
string propertyName = reader.GetString()!;
|
|
|
|
|
|
|
|
|
|
|
|
if (!double.TryParse(propertyName, NumberStyles.Float, Culture, out double double_Value))
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new JsonException($""Невалидное числовое значение в ключе свойства JSON: '{propertyName}' для метрики {nameof({typeNameZ})}."");
|
2026-06-05 12:13:35 +07:00
|
|
|
|
}
|
2026-06-07 15:54:53 +07:00
|
|
|
|
|
|
|
|
|
|
return new(double_Value);
|
2026-06-05 12:13:35 +07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
";
|
|
|
|
|
|
|
|
|
|
|
|
return template
|
|
|
|
|
|
.Replace("{ns}", ns)
|
|
|
|
|
|
.Replace("{typeName}", typeName)
|
|
|
|
|
|
.Replace("{typeNameA}", typeNameA)
|
|
|
|
|
|
.Replace("{typeNameB}", typeNameB)
|
|
|
|
|
|
.Replace("{typeNameZ}", typeNameZ);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private readonly struct StructInfo(string ns, string name, string a, string b, string z)
|
|
|
|
|
|
{
|
|
|
|
|
|
public string Namespace { get; } = ns;
|
|
|
|
|
|
public string TypeName { get; } = name;
|
|
|
|
|
|
public string TypeNameA { get; } = a;
|
|
|
|
|
|
public string TypeNameB { get; } = b;
|
|
|
|
|
|
public string TypeNameZ { get; } = z;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|