Общий метод расширения для плавающего числа?

В .Net 7 есть IFloatingPoint. Я прочитал следующий код для .Net 6. Он использует struct, IComparable, IFormattable, IConvertible, IComparable<T>, IEquatable<T>. Нужны ли все эти ограничения?

Код:

using System;

namespace MyExtensions
{
    public static class NumericExtensions
    {
        public static T Round<T>(this T value, int decimalPlaces) where T : 
            struct, IComparable, IFormattable, IConvertible, IComparable<T>, IEquatable<T>
        {
            decimal decimalValue = Convert.ToDecimal(value);
            decimal rounded = Math.Round(decimalValue, decimalPlaces);
            return (T)Convert.ChangeType(rounded, typeof(T));
        }
    }
}

(1) Он, безусловно, компилируется и запускается без ограничений типа. Необходимо для чего? (2) Это уже мусорный метод, который выбрасывает большие значения double. Я не вижу смысла в создании этого универсального типа, если он просто испортит данные, хранящиеся в универсальном типе. Наверняка задуман программистом на C++.

Wyck 09.12.2022 21:23

(1) Добавление ограничения типа struct может предотвратить использование метода в качестве "abc".Round(3). Какова цель добавления IFormattable, IConvertible и т. д.? (это не мой код) (2) я не хочу писать несколько функций для float, double, decimal и т.д.

ca9163d9 09.12.2022 21:42

Если вам нужна производительность, общий метод не подходит. Я бы просто избавился от метода расширения и вызывал Math.Round() там, где вам нужно.

Gabriel Luci 09.12.2022 21:52

Что это значит: «ИИ дал следующий метод»?

Flydog57 09.12.2022 21:53

Уже есть Math.Round перегрузки для double и decimal. Что еще вы хотите округлить? Если вам нужно float, напишите простой метод, который переводит число с плавающей запятой в двойное и возвращает результат обратно в число с плавающей запятой. Ваш общий результат заключается в том, что каждый вызов проходит по блоку перед возвратом

Flydog57 09.12.2022 21:59

код на самом деле из чата GCP" - posting code from ChatGPT is not allowed. stackoverflow.com/help/gpt-policy. Откуда мы знаем, что ваш код не получен из другого сообщения на SO? У вас даже нет ссылки на ChatGPT в вашем посте, не говоря уже об окончательном авторе, который, насколько нам известно, является электронной книгой, отсканированной ChatGPT.

user585968 09.12.2022 22:22

Re: ЧатГПТ. Это довольно хороший код, учитывая, что он был написан компьютером, который понятия не имеет, что он делает. Конечно, это читается так, как будто это было написано кем-то (/чем-то), кто понятия не имел, что делает (и определенно не программистом на C++ :-))

Flydog57 09.12.2022 22:59

@ Flydog57 Да, наверное, сгоряча. ;) "ChatGP" - лолз согласился! :D

user585968 09.12.2022 23:44

ОК обновил вопрос. На самом деле не так важно, откуда исходный код.

ca9163d9 10.12.2022 23:54
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
10
123
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Округление имеет смысл только для чисел с плавающей запятой. В C# у нас есть только три типа чисел с плавающей запятой (float, double, decimal). Методы Math.Round существуют в двух вариантах: один для double и один для decimal. Оба используют разные алгоритмы округления внутри. Использование метода округления для удвоения десятичных дробей или наоборот может привести к неожиданным результатам.

Поскольку у нас есть только три соответствующих типа, самый простой способ создания методов расширения — написать по одному для каждого типа. Для каждого типа достаточно одной строки:

public static class NumericExtensions
{
    public static double Round(this double value, int decimalPlaces) => Math.Round(value, decimalPlaces);
    public static decimal Round(this decimal value, int decimalPlaces) => Math.Round(value, decimalPlaces);
    public static float Round(this float value, int decimalPlaces) => (float)Math.Round(value, decimalPlaces);
}

Начиная с .NET 7 числовые типы в платформе были расширены для реализации универсальных интерфейсов, упрощающих написание универсальных методов, работающих с числами. Теперь также есть методы Round() для самих типов с плавающей запятой, так что нам больше не нужно использовать Math.Round(), но можно использовать метод Round() из фактического типа.

Благодаря этой новой поддержке мы можем написать единый метод расширения, который поддерживает все типы с плавающей запятой (включая новый тип Half):

public static class NumericExtensions
{
    public static T Round<T>(this T value, int decimalPlaces) where T : IFloatingPoint<T> => T.Round(value, decimalPlaces);
}

Я полностью согласен с подходом к округлению, который вы дали. А в .Net 7 IFloatingPoint является идеальным ограничением для универсального. Предположим, нам нужен общий метод для метода с плавающей запятой до .Net 7, является ли struct, IComparable, IFormattable, IConvertible, IComparable<T>, IEquatable<T> лучшей попыткой для IFloatingPoint?

ca9163d9 10.12.2022 23:42

Даже с этими ограничениями метод расширения будет доступен для таких типов, как int и DateTime, где округление не имеет смысла. В более старых версиях нет ограничений универсального типа, которые будут соответствовать типам с плавающей запятой, но не другим типам.

NineBerry 10.12.2022 23:59

Другие вопросы по теме