Создайте много типов структур, которые имеют ту же функциональность, что и float (System.Single) - PullRequest
0 голосов
/ 28 ноября 2018

Я создал кодовую базу, в которой сильно полагаюсь на структуру float.Но поплавок может означать что угодно.Секунды, метры, радианы, килограммы, метры в секунду, радианы в секунду и т. Д. Правильное именование помогает, но все равно легко все перемешать.Поэтому я начал писать структуры, которые обертывают поплавки, для каждой единицы.Но становится все труднее писать структуры, которые:

  • хранят базовое значение с плавающей запятой
  • всех их операторов (<, <=,>,> =, ==,! =,-, +, *, /)
  • правильный метод Equals, GetHashCode и ToString
  • Реализация интерфейса IEquatable

Какой самый простой способгенерировать такие структуры, чтобы мне не пришлось поддерживать так много кода?

Бонусные вопросы: Таким образом, я все еще могу добавить некоторые специальные операторы.Например, я хотел бы добавить оператор, который превращает Meters / Seconds в MetersPerSecond.

Редактировать: я нахожусь на .Net Framework 4.7 и уровне языка C # 7.3

Вот мой пример Seconds struct.Как вы можете себе представить, структура Meters выглядит точно так же.

public struct Seconds : IEquatable<Seconds>
{
    public Seconds(float value)
    {
        this.Value = value;
    }

    public float Value { get; }

    public static implicit operator Seconds(float value) => new Seconds(value);

    public static implicit operator Seconds(TimeSpan value) => new Seconds((float)value.TotalSeconds);

    public static Seconds operator +(Seconds a, Seconds b) => new Seconds(a.Value + b.Value);

    public static Seconds operator -(Seconds a, Seconds b) => new Seconds(a.Value - b.Value);

    public static bool operator >(Seconds a, Seconds b) => a.Value > b.Value;

    public static bool operator <(Seconds a, Seconds b) => a.Value < b.Value;

    public static bool operator >=(Seconds a, Seconds b) => a.Value >= b.Value;

    public static bool operator <=(Seconds a, Seconds b) => a.Value <= b.Value;

    public static bool operator ==(Seconds a, Seconds b) => a.Equals(b);

    public static bool operator !=(Seconds a, Seconds b) => !a.Equals(b);

    public override int GetHashCode() => this.Value.GetHashCode();

    public override bool Equals(object obj)
    {
        if (obj is Seconds)
        {
            return this.Equals((Seconds)obj);
        }

        return false;
    }

    public bool Equals(Seconds other) => other.Value == this.Value;

    public override string ToString() => $"{this.Value.ToString("F2", CultureInfo.InvariantCulture)}s";
}   

Ответы [ 2 ]

0 голосов
/ 30 ноября 2018

Если вы хотите остаться с C #, вы можете использовать простой шаблон Yellicode для генерации стандартного кода (используя немного TypeScript).Вот шаблон, который генерирует частичные структуры (struct-types.template.ts).

import { Generator, TextWriter } from '@yellicode/templating';
import { CSharpWriter } from '@yellicode/csharp';

var structNames = ['Seconds', 'Meters']; // add more names here 

Generator.generate({ outputFile: './structs.cs' }, (output: TextWriter) => {
    var csharp = new CSharpWriter(output);
    structNames.forEach(structName => {     
        const struct: StructDefinition = { name: structName, accessModifier: 'public', isPartial: true, implements: [`IEquatable<${structName}>`] } as StructDefinition;
        csharp.writeStructBlock(struct, () => {
            // Ctor            
            csharp.writeMethodBlock({ isConstructor: true, name: structName, accessModifier: 'public', parameters: [{ typeName: 'float', name: 'value' }] }, () => {
                csharp.writeLine('this.Value = value;');
            });
            csharp.writeLine();
            // Value            
            csharp.writeAutoProperty({ typeName: 'float', name: 'value', accessModifier: 'public', hasGetter: true });
            csharp.writeLine();
            // Operators 
            csharp.writeLine(`public static implicit operator ${structName}(float value) => new ${structName}(value);`);
            csharp.writeLine();
            // ... other operators omitted for brevity, type-specific conversion operators would be in a partial file
            // Methods
            csharp.writeLine('public override int GetHashCode() => this.Value.GetHashCode();');
            csharp.writeLine();
            // ... other methods omitted for brevity
        })
        csharp.writeLine();
    })
}); 

Файл конфигурации (codegenconfig.json) должен выглядеть следующим образом:

{
    "compileTypeScript": true,
    "templates": [
        {
           "templateFile": "struct-types.template.ts"
        }
    ]
}

Быстрый запуск (убедитесь, что у вас установлен NPM, затем откройте командную строку):

  1. npm install @yellicode/cli -g
  2. Создайте каталог с вышеуказанными файлами и запустите npm init -y
  3. npm install --save-dev @yellicode/templating @yellicode/csharp
  4. Запустите yellicode --watch, чтобы сгенерировать вашcode.

Если вам нужен отдельный выходной файл для каждой структуры, начните с цикла structNames.forEach(.. и вызовите Generator.generate(... для каждой структуры.

0 голосов
/ 28 ноября 2018

Попробуйте Единицы измерения функция в F #.Он обеспечивает единицу измерения во время компиляции, не влияет на производительность.Сборка, выполненная в F #, может быть легко использована из C #, если общественная поверхность остается простой.Единицы измерения, наложенные на поплавок, компилируются в System.Double в IL.

Что касается бонуса, единицы измерения поддерживаются и проверяются компилятором.Если счетчики делятся на секунды, результат будет в метрах в секунду.

...